如何使用reader monad的函数实例?

时间:2013-12-25 00:31:48

标签: haskell monads

我发现了这个monad的有趣用法:

Prelude Control.Monad> liftM2 (,) head tail $ [1..5]
(1,[2,3,4,5])

看起来有用的技术允许r中的(->) r只传递一次,我希望这个表达式首先需要复制列表。

我不太明白提升实际上是如何起作用的。隐藏了>>=return的位置?有什么其他常见情况会要求使用这个特定的实例?

2 个答案:

答案 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):传递给(>>=)的每个值(当你的例子中的headtail)在组合(monadic)函数应用于该参数时,会传递相同的参数([1,..5])。

不使用monadic liftM2,(函数应用程序)表达式(,) head tail只创建一个元组(head, tail)。但是当(在liftM2中)应用monadic绑定而不是“普通”函数应用程序时,这些参数被绑定(“绑定”)到monadic值,在那里它们保持“准备好”以接收绑定结果函数参数。

另请注意,对r = [1..5]的每次调用都会使用一次最终参数((>>=))(在liftM2中会发生两次,这就是2的含义)。 return不会导致最后一个参数的使用,因为在这个monad中我们有return f r = const f rf r为显式添加),忽略了参数r