Following the amazing Haskell Programming book, I was stuck for a while on the Monad chapter.
An exercise asks to write a List
data type, implement its Functor
, Applicative
and Monad
instances and then test them with QuickCheck and Checkers.
Having this data type:
data List a =
Nil
| Cons a (List a)
deriving (Eq, Show)
I had write its Arbitrary
instance to generate values for the tests.
There’s a useful function in QuickCheck called sized that can be used for this.
The type signature is:
sized :: (Int -> Gen a) -> Gen a
What’s needed to use it is a function that takes a Int
and returns a Gen a
.
This is the function I ended up with:
arbitraryList :: Arbitrary a => Int -> Gen (List a)
arbitraryList m
| m == 0 = return Nil
| m > 6 = arbitraryList 6
| otherwise = Cons <$> arbitrary <*> (arbitraryList (m-1))
I capped the length at 6 to avoid super long lists.
The Arbitrary
instance is then:
instance Arbitrary a => Arbitrary (List a) where
arbitrary = sized arbitraryList