I have found an interesting use of this monad:
Prelude Control.Monad> liftM2 (,) head tail $ [1..5]
(1,[2,3,4,5])
It looks like useful technique that allows r
in (->) r
to be passed only once, where I would expect this expression to require duplicating the list first.
I don't quite understand how lifting actually works here. Where is >>=
or return
hidden? What are other common situations which would call for using this particular instance?
liftM2
takes a binary function and two monadic values and applies the function over the values inside the monad. Look at the implementation:
liftM2 :: (Monad m) => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r
liftM2 f m1 m2 = do
x1 <- m1
x2 <- m2
return (f x1 x2)
Or if we desugar it we can see the explicit (>>=)
and return
:
liftM2 :: (Monad m) => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r
liftM2 f m1 m2 =
m1 >>= (\x1 ->
m2 >>= (\x2 ->
return (f x1 x2)))
This is useful whenever you have a need to apply a pure function inside a monad, the use cases are pretty wide since it's a very common task.
(Read freyrs's answer first; this answer expands upon it.)
See the defintion of the reader/Function monad instance
instance Monad ((->) r) where
return = const
f >>= k = \ r -> k (f r) r
You can see there where the input gets duplicated/forked ( r
appears twice on the right-hand-side of the \\ r
expression): Each value that is passed to (>>=)
(both head
and tail
, in your example) is then passed the same argument ( [1,..5]
) when the combined (monadic) function is applied to that argument.
Without using monadic liftM2
, the (function application) expression (,) head tail
just creates a tuple (head, tail)
. But when (as in liftM2
) monadic bind is applied instead of "plain" function application, those arguments are bound ("bind-ed") into the monadic value, where they remain "ready" to receive the bind result's function argument.
Note also that the final argument ( r = [1..5]
) is used once for each call to (>>=)
(which happens twice in liftM2
, that's what the 2
means). The return
causes no additional use of the final argument, since in this monad we have return fr = const fr
( fr
added for explicitness), which ignores the argument r
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.