我发现了这个monad的有趣用法:
Prelude Control.Monad> liftM2 (,) head tail $ [1..5]
(1,[2,3,4,5])
看起来有用的技术允许r
中的(->) r
只传递一次,我希望这个表达式首先需要复制列表。
我不太明白提升实际上是如何起作用的。隐藏了>>=
或return
的位置?有什么其他常见情况会要求使用这个特定的实例?
答案 0 :(得分:2)
liftM2
采用二元函数和两个monadic值,并将函数应用于monad中的值。看看实现:
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)
或者,如果我们去除它,我们可以看到明确的(>>=)
和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)))
只要你需要在monad中应用纯函数,这很有用,用例非常广泛,因为它是一个非常常见的任务。
答案 1 :(得分:1)
(首先阅读freyrs's answer;这个答案会扩展到它。)
请参阅the defintion of the reader/Function monad instance
instance Monad ((->) r) where
return = const
f >>= k = \ r -> k (f r) r
您可以看到输入被重复/分叉的位置(r
表达式的右侧出现两次\ r
):传递给(>>=)
的每个值(当你的例子中的head
和tail
)在组合(monadic)函数应用于该参数时,会传递相同的参数([1,..5]
)。
不使用monadic liftM2
,(函数应用程序)表达式(,) head tail
只创建一个元组(head, tail)
。但是当(在liftM2
中)应用monadic绑定而不是“普通”函数应用程序时,这些参数被绑定(“绑定”)到monadic值,在那里它们保持“准备好”以接收绑定结果函数参数。
另请注意,对r = [1..5]
的每次调用都会使用一次最终参数((>>=)
)(在liftM2
中会发生两次,这就是2
的含义)。 return
不会导致最后一个参数的使用,因为在这个monad中我们有return f r = const f r
(f r
为显式添加),忽略了参数r
。