Why doesn't monad take `(M a -> M b)`?
https://softwareengineering.stackexchange.com/questions/230524
-
02-10-2020 - |
Question
All apologies -- I'm still very much on the outside of Haskell looking in.
Why does the bind for a monad have this signature:
M a -> (a -> M b) -> M b
and not
M a -> (M a -> M b) -> M b
i.e. a function that takes M a
instead of just a
a
is available to the function in both, but the context that M
provides is not available to the function in the 1st. Just the lifted value itself.
(If that's a silly question, just downvote me a lot & I'll delete it... like I say, still very much on the outside looking in)
Solution
Just a hint: a -> M b
is more general than M a -> M b
, since you can do a -> M a
any time with return
.
OTHER TIPS
Let’s call functions that return a monadic value “actions”.
The type signature for >>=
in p >>= q
says that:
- Given a nullary action
p
that returns something of typea
- And given a unary action
q
that takes ana
and returns something of typeb
- You can chain them to get a nullary action that returns something of type
b
It is worth remembering that >>=
has a flipped version: =<<
, that might be easier to understand visually—it corresponds to function application in a monad:
($) :: (a -> b) -> a -> b
(=<<) :: (a -> m b) -> m a -> m b
Whereas $
is application of a pure function to a pure argument:
succ $ 2 + 2
=<<
is application of a side-effectful function to a side-effectful argument:
putStrLn =<< readLine
And you may have seen the Applicative operator <$>
(an alias for fmap
), which is for the other common case of pure functions with side-effecting arguments:
lines <$> readFile "input.txt"