A few days ago I was trying to prove monad laws by creating a new monad instance but I found myself stuck at defining the new monad instance.
{-# LANGUAGE DeriveFunctor, InstanceSigs #-}
import Control.Monad
newtype Test a = Test { getTest :: [Maybe a] }
deriving Functor
instance Applicative Test where
pure = return
(<*>) = liftM2 ($)
instance Monad Test where
return :: a -> Test a
return a = Test $ [Just a]
(>>=) :: Test a -> (a -> Test b) -> Test b
g >>= f = concat (map f g) --Tried to do something like this
I tried something following the list monad definition, but is stuck because concat expects [[a]] but here it gets [Test b], so maybe there are other functions available or is there a way to make concat work on the newType? Any suggestions are appreciated. Thanks.
Unlike type
aliases, newtype
wrappers need to be manually applied and removed. Replace g >>= f = concat (map f g)
with Test g >>= f = Test $ concat (map (getTest . f) g)
.
This will leave you with only one more type error: g
has type [Maybe a]
instead of the needed [a]
. We can tack on a catMaybes
(needs import Data.Maybe
) to take care of that: Test g >>= f = Test $ concat (map (getTest . f) $ catMaybes g)
. Now it compiles.
Unfortunately, this instance isn't lawful. I'll leave it as an exercise for the reader to establish why not, and whether it can be easily fixed.