I am working through the Haskell Book and have come to the point of writing an Arbitrary instance for newType Comp
. The code is below
instance Show (Comp a) where
show f = "Unicorns!!"
newtype Comp a =
Comp { unComp :: (a -> a) }
instance (Semigroup a) => S.Semigroup (Comp a) where
(Comp fx) <> (Comp fy) = Comp (fx . fy)
instance (CoArbitrary a, Arbitrary a) => Arbitrary (Comp a) where
arbitrary = do
f <- Test.QuickCheck.arbitrary
return (Comp f)
type CompAssoc = String -> Comp String -> Comp String -> Comp String -> Bool
compAssoc :: (S.Semigroup a, Eq a) => a -> Comp a -> Comp a -> Comp a -> Bool
compAssoc v a b c = (unComp (a <> (b <> c)) $ v) == (unComp ((a <> b) <> c) $ v)
and tested with
main :: IO ()
main = do
quickCheck (compAssoc :: CompAssoc)
My question revolves around the Arbitrary instance. It is generating a function to be passed to return (Comp f)
. I understand (though not fully why) that this has to be scoped to CoArbitrary. But if that thing passed to return (Comp f)
is CoArbitrary
, how can it also be Arbitrary
? I guess it seems to be like these constraints both refer to the pass/return type of the function and the function itself. I'm a little confused.