The below code fails the checkers test for traversable. I'd appreciate an explanation of why it fails, not just how to fix it.
import Test.QuickCheck
import Test.QuickCheck.Checkers
import Test.QuickCheck.Classes
data List a =
Nil
| Cons a (List a)
deriving (Show, Eq, Ord)
instance Functor List where
fmap _ Nil = Nil
fmap f (Cons x xs) = (Cons (f x) (fmap f xs))
instance Foldable List where
foldr f z (Cons x xs) = f x z
foldr _ z Nil = z
instance Traversable List where
traverse f Nil = pure Nil
-- traverse f (Cons x Nil) = Cons <$> f x <*> pure Nil
traverse f (Cons x xs) = Cons <$> f x <*> (traverse f xs)
instance Arbitrary a => Arbitrary (List a) where
arbitrary = sized go
where go 0 = pure Nil
go n = do
xs <- go (n - 1)
x <- arbitrary
return (Cons x xs)
type TI = List
instance Eq a => EqProp (List a) where (=-=) = eq
main = do
let trigger = undefined :: TI (Int, Int, [Int])
-- quickBatch (functor trigger)
quickBatch (traversable trigger)
Here you see that it passes the fmap
laws, but not the foldMap
ones:
λ> main
traversable:
fmap: +++ OK, passed 500 tests.
foldMap: *** Failed! Falsifiable (after 6 tests):
<function>
Cons 4 (Cons (-2) (Cons (-5) (Cons 5 (Cons 2 Nil))))
instance Foldable List where
foldr f z (Cons x xs) = f x z
foldr _ z Nil = z
Your Foldable instance doesn't traverse the tail of the list.
checkers
tests your Traversable
instances by testing Functor
and Foldable
all together: it derives foldMap
and fmap
from your implementation of Traversable
and make sure they produce the same result as foldMap
and fmap
you defined.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With