Reputation: 41909
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:
Arbritrary
instance for a new
data type (such as my Cons a
)?Gen (Cons Int)
- makeArbitraryCons
?quickCheck
second_functor_law_int
?Upvotes: 0
Views: 677
Reputation: 52029
1 & 2. You can either: define an Arbitrary
instance or create a Gen ...
function and use something like the forAll
combinator.
See this answer for an example of using forAll
with a Gen ...
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 random Int -> 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 have Show
instances.
With what you have it is possible to call quickCheck
with specific functions f
and g
, e.g.:
quickCheck $ second_functor_law_int_int (+1) (*2)
Then QuickCheck will only generate random Cons Int
values.
Btw, a better way to define arbitrary
for an ADT like Cons
is to use sized
. Some examples:
Upvotes: 1