Reputation: 93
I need to declare a Monad instance for an specific data type:
data M m a = Mk (m (Maybe a))
instance (Monad m) => Monad (M m) where
return x = Mk (m (Just x))
Mk (m (Nothing)) >>= f = Mk (m (Nothing))
Mk (m (Just x)) >>= f = f x
But I get:
test.hs:6:7: Parse error in pattern: m
Failed, modules loaded: none.
It may be very simple, but I cant figure it out!
Upvotes: 2
Views: 192
Reputation: 8831
You can only pattern match on a constructor, not on anything else. You'll have to use the Monad instance for m to get to the Maybe data that's inside. I'm not 100% sure that this has the behavior you want, but it does typecheck.
data M m a = Mk (m (Maybe a))
instance (Monad m) => Monad (M m) where
return x = Mk (return (Just x))
Mk m >>= f = Mk (m >>= go)
where go (Just x) = let Mk x' = f x in x'
go _ = return Nothing
Upvotes: 0
Reputation: 77404
The type variable m
is not something you can pattern match on, especially not in order to distinguish between Just
and Nothing
. Think about what it would mean for different possible types used in place of m
--in many cases, such a pattern match would be outright impossible.
To write that instance, you'll need something like this:
instance (Monad m) => Monad (M m) where
return x = Mk (return (Just x))
Mk mx >>= f = -- ??
Note the return
used to create a value of type m (Maybe a)
--that's possible because of the Monad m
constraint, and in the general case (with no constraint at all) there'd be no way to create such a value.
To implement (>>=)
you'll need to do something similar, likewise making use of (>>=)
for the Monad
instance of m
.
Incidentally, you should consider using a newtype
for M
, unless you have a specific reason for wanting data
. Most of the time, if you can use newtype
, you should.
Upvotes: 5