With the following Algebraic Data Type:
data Cons a = Cons a (Cons a) | Empty deriving (Show, Eq)
I wrote an instance of Arbitrary:
My understanding is that it's necessary to create an instance of Arbitrary for QuickCheck to know how to find a Cons Int to plug in for its tests.
instance Arbitrary (Cons Int) where
    arbitrary = elements [Empty, Cons 10 (Cons 100 (Cons 55 Empty)), Cons 1 Empty]
and a function:
makeArbitraryCons :: Gen (Cons Int)
makeArbitraryCons = arbitrary 
Then, I wrote a QuickCheck test:
prop_id_functor_law_int ::  Cons Int -> Bool
prop_id_functor_law_int x = fmap id x == id x
And it works:
ghci> quickCheck prop_id_functor_law_int
*** Failed! Falsifiable (after 1 test):
Cons 10 (Cons 100 (Cons 55 Empty))
However, when I try to run the following test, it fails:
second_functor_law_int :: (Int -> Int) -> (Int -> Int) -> Cons Int -> Bool
second_functor_law_int f g x = left == right
  where left = fmap (f . g) $ x
        right = (fmap f) . (fmap g) $ x
with this error:
ghci> quickCheck second_functor_law_int
<interactive>:418:1:
    No instance for (Show (Int -> Int))
      arising from a use of `quickCheck'
    In the expression: quickCheck second_functor_law_int
    In an equation for `it': it = quickCheck second_functor_law_int
My questions are:
- is it necessary to define an 
Arbritraryinstance for a new data type (such as myCons a)? - must I create a function that
creates a 
Gen (Cons Int)-makeArbitraryCons? - lastly, what's going on when I run my second test via 
quickCheck second_functor_law_int? 
                        
1 & 2. You can either: define an
Arbitraryinstance or create aGen ...function and use something like theforAllcombinator.See this answer for an example of using
forAllwith aGen ...function.The signature of
second_functor_law_intis:second_functor_law :: (Int -> Int) -> (Int -> Int) -> Cons Int -> Bool
so by running
quickCheck second_functor_law_intyou are asking QuickCheck to create a randomInt -> Intfunction. Quickcheck requires its randomly generated arguments to be Show-able, and so you are getting this error since functions (in general) do not haveShowinstances.With what you have it is possible to call
quickCheckwith specific functionsfandg, e.g.:Then QuickCheck will only generate random
Cons Intvalues.Btw, a better way to define
arbitraryfor an ADT likeConsis to usesized. Some examples: