From the Haskell Book chapter on Monoids, I am writing quickcheck tests for
semigroupAssoc :: (Eq m, S.Semigroup m) => m -> m -> m -> Bool
semigroupAssoc a b c =
(a S.<> (b S.<> c)) == ((a S.<> b) S.<> c)
type IdentAssoc = Identity String -> Identity String -> Identity String -> Bool
, invoking with
quickCheck (semigroupAssoc :: IdentAssoc)
Here is the arbitrary typeclass instance
instance (Arbitrary a) => Arbitrary (Identity a) where
arbitrary = do
a <- Test.QuickCheck.arbitrary
return (Identity a)
My question is that in my arbitrary instance, I can return either (Identity a) or just a. (Identity a) is correct, but just a gives no compiler error and causes an infinite loop when run. Why is this?
Type inference changes the arbitrary
call to point at the same instance we are defining right now, causing an infinite loop.
instance (Arbitrary a) => Arbitrary (Identity a) where
arbitrary = do
x <- Test.QuickCheck.arbitrary -- this calls arbitrary @ a
return (Identity x)
instance (Arbitrary a) => Arbitrary (Identity a) where
arbitrary = do
x <- Test.QuickCheck.arbitrary -- this calls arbitrary @ (Identity a)
return x
Every time we call a class method, the compiler infers which instance to call.
In the former case, the compiler infers x :: a
(only this type makes the code type check!), hence it calls arbitrary @ a
.
In the latter case, the compiler infers x :: Identity a
(only this type makes the code type check!), hence it calls arbitrary @ (Identity a)
, causing the infinite loop.