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?
A monad is an algebraic structure in category theory, and in Haskell it is used to describe computations as sequences of steps, and to handle side effects such as state and IO. Monads are abstract, and they have many useful concrete instances. Monads provide a way to structure a program.
Monads are simply a way to wrapping things and provide methods to do operations on the wrapped stuff without unwrapping it. For example, you can create a type to wrap another one, in Haskell: data Wrapped a = Wrap a. To wrap stuff we define return :: a -> Wrapped a return x = Wrap x.
So in simple words, a monad is a rule to pass from any type X to another type T(X) , and a rule to pass from two functions f:X->T(Y) and g:Y->T(Z) (that you would like to compose but can't) to a new function h:X->T(Z) . Which, however, is not the composition in strict mathematical sense.
monadic operation (unary operation) defined on a set S. A function from the domain S into S itself. The identity function is a monadic operation. Other examples are the operations of negation in arithmetic or logic and of taking complements in set theory or in Boolean algebra.
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)
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With