简体   繁体   English

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

[英]How to use function instance of reader monad?

I have found an interesting use of this monad:我发现了这个 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.它看起来是一种有用的技术,它允许r in (->) r只传递一次,我希望这个表达式首先需要复制列表。

I don't quite understand how lifting actually works here.我不太明白这里的提升实际上是如何工作的。 Where is >>= or return hidden? >>=return隐藏在哪里? 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. liftM2采用一个二元函数和两个liftM2值,并将该函数应用于 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 :或者,如果我们对其进行脱糖,我们可以看到显式(>>=)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.当您需要在 monad 中应用纯函数时,这很有用,用例非常广泛,因为这是一项非常常见的任务。

(Read freyrs's answer first; this answer expands upon it.) (首先阅读freyrs 的回答;这个回答对此进行了扩展。)

See the defintion of the reader/Function monad instance查看reader/Function monad 实例的定义

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.您可以在那里看到输入被复制/分叉的位置( r\\ r表达式的右侧出现两次):传递给(>>=)每个值(>>=)在您的示例中为headtail )当组合(monadic)函数应用于该参数时[1,..5]然后传递相同的参数( [1,..5] )。

Without using monadic liftM2 , the (function application) expression (,) head tail just creates a tuple (head, tail) .不使用liftM2 ,(函数应用)表达式(,) head tail只是创建一个元组(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.但是当(如在liftM2 )应用liftM2 bind而不是“普通”函数应用程序时,这些参数被绑定(“bind-ed”)到monadic值中,在那里它们保持“准备好”接收绑定结果的函数参数。

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).另请注意,最后一个参数 ( r = [1..5] ) 用于每次调用(>>=) (在liftM2中发生两次,这就是2意思)。 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 . return不会导致对最后一个参数的额外使用,因为在这个 monad 中我们有return fr = const fr (为了明确而添加fr ),它忽略了参数r

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM