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
Arbritrary
instance 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
Arbitrary
instance or create aGen ...
function and use something like theforAll
combinator.See this answer for an example of using
forAll
with aGen ...
function.The signature of
second_functor_law_int
is:second_functor_law :: (Int -> Int) -> (Int -> Int) -> Cons Int -> Bool
so by running
quickCheck second_functor_law_int
you are asking QuickCheck to create a randomInt -> Int
function. Quickcheck requires its randomly generated arguments to be Show-able, and so you are getting this error since functions (in general) do not haveShow
instances.With what you have it is possible to call
quickCheck
with specific functionsf
andg
, e.g.:Then QuickCheck will only generate random
Cons Int
values.Btw, a better way to define
arbitrary
for an ADT likeCons
is to usesized
. Some examples: