nicoan
nicoan

Reputation: 93

Pattern matching error on instance declaration

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

Answers (2)

Dirk Holsopple
Dirk Holsopple

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

C. A. McCann
C. A. McCann

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

Related Questions