Reputation: 3331
I am going through the Haskell Book and the chapter on applicatives started using the checkers library for testing.
This library introduces the EqProp
typeclass, and I don't understand how it differs from Eq
. Most of the examples that call for EqProp
use Eq
under the hood anyway.
Why do people use checkers over QuickCheck?
Upvotes: 3
Views: 436
Reputation: 34378
This library introduces the
EqProp
typeclass, and I don't understand how this differs fromEq
.
(==)
from Eq
gives you a Bool
; (=-=)
from EqProp
gives you a QuickCheck Property
. If you have an instance of Eq
, you can also make it an EqProp
instance, as witnessed by eq
. The interesting instances of EqProp
are those that aren't instances of Eq
, such as functions (cf. Li-yao Xia's answer).
Why do people use checkers over Quickcheck?
Checkers is a set of extra tools built upon QuickCheck. As its readme and Hackage description suggest, one of its goals is making it easy to express class laws as Quickcheck properties. For instance, note how the definition of the applicative
"test batch", which I will quote below, looks a lot like how we often write the Applicative
laws, and is nicely self-documenting.
(Feel free to skip the bookkeeping constraints in the top-level signature. Also note that the m (a,b,c)
argument is, in a simplest-thing-that-could-possibly-work fashion, only used for type specialisation, the intent being that you pass e.g. undefined :: [(Int,Int,Int)]
to test the list instance of Applicative
.)
-- | Properties to check that the 'Applicative' @m@ satisfies the applicative
-- properties
applicative :: forall m a b c.
( Applicative m
, Arbitrary a, CoArbitrary a, Arbitrary b, Arbitrary (m a)
, Arbitrary (m (b -> c)), Show (m (b -> c))
, Arbitrary (m (a -> b)), Show (m (a -> b))
, Show a, Show (m a)
, EqProp (m a), EqProp (m b), EqProp (m c)
) =>
m (a,b,c) -> TestBatch
applicative = const ( "applicative"
, [ ("identity" , property identityP)
, ("composition" , property compositionP)
, ("homomorphism", property homomorphismP)
, ("interchange" , property interchangeP)
, ("functor" , property functorP)
]
)
where
identityP :: m a -> Property
compositionP :: m (b -> c) -> m (a -> b) -> m a -> Property
homomorphismP :: (a -> b) -> a -> Property
interchangeP :: m (a -> b) -> a -> Property
functorP :: (a -> b) -> m a -> Property
identityP v = (pure id <*> v) =-= v
compositionP u v w = (pure (.) <*> u <*> v <*> w) =-= (u <*> (v <*> w))
homomorphismP f x = (pure f <*> pure x) =-= (pure (f x) :: m b)
interchangeP u y = (u <*> pure y) =-= (pure ($ y) <*> u)
functorP f x = (fmap f x) =-= (pure f <*> x)
Upvotes: 3
Reputation: 33464
The point is that functions and infinite values do not have decidable equality (Eq
), but can be tested for it (EqProp
) by observing a (random) finite fragment.
Upvotes: 2