Reputation: 491
I'm trying to do a wrapper newtype for my Ap ZipList
based on the advice given at Haskell quickBatch testing: Applicative Monoid ZipList. My version of GHC is 8.8.4 and I compile using stack. My full code:
newtype Ap f a = Ap { getAp :: f a }
deriving (Eq, Show)
instance (Applicative f, Semigroup a) =>
Semigroup (Ap f a) where
Ap xs <> Ap ys =
Ap $ liftA2 (<>) xs ys
instance (Applicative f, Monoid a) =>
Monoid (Ap f a) where
mempty = Ap $ pure mempty
Ap xs `mappend` Ap ys =
Ap $ liftA2 mappend xs ys
app :: Ap ZipList (Sum Int)
app = Ap (ZipList [1,2 :: Sum Int])
test :: Ap ZipList (Sum Int)
test = app <> app
instance Arbitrary (f a) =>
Arbitrary (Ap f a) where
arbitrary = Ap <$> arbitrary
instance Eq a => EqProp (Ap ZipList a) where
xs =-= ys = xs' `eq` ys' where
xs' =
let (Ap (ZipList l)) = xs
in take 3000 l
ys' =
let l = (getZipList . getAp) ys
in take 3000 l
newtype MonZipList a =
MonZipList (Ap ZipList a)
deriving (Semigroup, Monoid, Eq, Show)
deriving instance Functor f =>
Functor (Ap f)
deriving instance Applicative f =>
Applicative (Ap f)
monapp :: MonZipList (Sum Int)
monapp = MonZipList app
instance Arbitrary a =>
Arbitrary (MonZipList a) where
arbitrary = MonZipList <$> arbitrary
instance Eq a => EqProp (MonZipList a) where
(=-=) = eq
main :: IO ()
main = do
quickBatch $ monoid app
quickBatch $ monoid monapp
quickBatch $ functor monapp
quickBatch $ applicative monapp
The basic quickBatch $ monoid app
tests run well without problems.
The problems I face are that when I run quickBatch $ monoid monapp
, the monoid tests hangs at the mconcat test and could not be stopped. I had to close my WSL Bash in order to stop it from running.
When I tried quickBatch $ functor monapp
or quickBatch $ applicative monapp
, errors were thrown, thereby making the effectiveness of the wrapper newtype questionable:
Couldn't match type ‘Sum Int’ with ‘(a0, b0, c0)’
Expected type: MonZipList (a0, b0, c0)
Actual type: MonZipList (Sum Int)
In the first argument of ‘functor’, namely ‘monapp’
Are there any solutions to these newtype wrapper problems?
Upvotes: 0
Views: 58
Reputation: 3924
It looks like you're running into two separate problems, neither of which is really the result of using a newtype wrapper.
First, ZipList
has infinite lists under the hood in the case of mempty
, which is probably why your monoid monapp
test is hanging. It looks like you're taking care of this in your EqProp (Ap ZipList a)
instance, but not in your EqProp (MonZipList a)
instance. That's a little strange. Perhaps what you meant to do was to remove the EqProp (Ap ZipList a)
instance altogether and just have the EqProp (MonZipList a)
instance, but use the code from the EqProp (Ap ZipList a)
instance? Something like:
instance Eq a => EqProp (MonZipList a) where
MonZipList (Ap (ZipList xs)) =-= MonZipList (Ap (ZipList ys)) =
take 3000 xs `eq` take 3000 ys
As for functor monapp
, the types don't line up at all. For functor
and applicative
, you need to provide 3 arbitrary types for the tests to use.
You may not know this, but the actual value you provide to, e.g., functor
is irrelevant -- it's only interested in the types. Personally, I find it easier to just provide the types as arguments for these functions directly, as in:
{-# LANGUAGE TypeApplications #-}
main = do
quickBatch $ monoid @(MonZipList (Sum Int)) undefined
quickBatch $ functor @MonZipList @Int @Bool @Char undefined
quickBatch $ applicative @MonZipList @String @Int @Char undefined
Now it becomes clear what's going on: for the functor
tests, use the MonZipList
functor along with arbitrary (and coarbitrary) values from the types Int
, Bool
, and Char
for testing. You can feel free to change those types or to run multiple functor
tests if you really want to test it with other types too.
Upvotes: 2