I have some confusion with the function monad. The function monad is defined as follow:
instance Monad ((->) r) where
return x = \_ -> x
h >>= f = \w -> f (h w) w
I tried to play around with it by writing a binding operation:
( (*2) >>= (+10) ) 3
(return 3) :: ((->) Int)
But it caused errors. And I also try to rewrite a function AddStuff into the binding operations.
addStuff = do
a <- (*2)
b <- (+10)
return (a+b)
then convert this function into
addStuff' w = (*2) w >>= (\a ->
(+10) w >>= (\b ->
return (a+b) ))
I check the type of the new function as see
addStuff :: (Monad m, Num (m b), Num b) => m b -> m b
Why is that? How can I fix that?
In addStuff'
you write (*2) w
and (+10) w
. Those are equivalent to w*2
and w+10
respectively. So addStuff'
is equivalent to this:
addStuff' w = w*2 >>= \a ->
w+10 >>= \b ->
return (a+b)
Writing it this way should make it obvious that here the left operands to >>=
are numbers, not functions. That's why the inferred type is telling you that your function only works for numbers that are monads.
When eliminating do
notation the left operand to >>=
should be exactly the same as the right operand of <-
. Also eliminating do
notation does not add any arguments to the function. So the correct rewriting would look like this:
addStuff' = (*2) >>= \a ->
(+10) >>= \b ->
return (a+b)
As to why your earlier pieces of code don't work:
( (*2) >>= (+10) ) 3
The operator >>=
has type m a -> (a -> m b) -> m b
. For simplicity let's assume that all the numbers in this code have type Int
, then your left operand has type Int -> Int
or m Int
if m
is (->) Int
. So for some type b
the right operand should have type Int -> ((->) Int) b
or, more readably, Int -> Int -> b
. The type it actually has though is Int -> Int
. Therefore your expression is ill-typed.
(return 3) :: ((->) Int)
((->) Int)
has kind * -> *
- the type of a value must have kind *
.
Or to approach this differently: return 3
has type m Int
for some m
(still assuming that all integer literals have type Int
for simplicity). So if m
is `((->) Int)
, the type of return 3
will be ((->) Int) Int
or Int -> Int
, not ((->) Int)
.