Tillmann Rendel rendel at cs.au.dk
Sat May 9 16:36:49 EDT 2009

```michael rice wrote:
> Prelude> Just 3 >>= (1+)

Let's check the types.

Prelude> :t (>>=)
(>>=) :: (Monad m) => m a -> (a -> m b) -> m b

Prelude> :t Just 3
Just 3 :: (Num t) => Maybe t

Prelude> :t (1 +)
(1 +) :: (Num a) => a -> a

Renaming the variables in the type of (1 +) gives:

(1 +) :: (Num c) => c -> c

Since (Just 3) is the first argument of (>>=), we have to unify the
types (Maybe t) and (m a). This leads to:

m = Maybe
t = a

Since (1 +) is the second argument of (>>=), we have to unify the types
(c -> c) and (a -> m b). This leads to:

c = a = m b

Since we haven't found any inconsistencies, typechecking succeeded, and
we instantiate the types of Just 3, (>>=) and (1 +) to the following
types by applying the substituations we found.

Just 3 :: Num (Maybe b) => Maybe (Maybe b)
(1 +) :: Num (Maybe b) => Maybe b -> Maybe b
(>>=) :: Monad Maybe => Maybe (Maybe b) ->
(Maybe b -> Maybe b) -> Maybe b

And the type of the whole expression is accordingly:

Just 3 >>= (1 +) :: (Monad Maybe, Num (Maybe b)) => Maybe b

Now ghc looks at the constraints, figures out that Monad Maybe is fine,
and complains about Num (Maybe b).

Try the fmap function instead, it has the following type:

Prelude> :t fmap
fmap :: (Functor f) => (a -> b) -> f a -> f b

Since every self-respecting Monad is also a Functor, you can use

fmap (1 +) (Just 3).

Now (a -> b) is unified with (Num a => a -> a), so that the overall type
of the function is (Num a => Maybe a) as you would expect.

Tillmann
```