简体   繁体   English

函数上下文中一元计算的先前值是多少?

[英]What is the previous value of a monadic computation in the function context?

I am struggeling with the function instance of monads (who does not?).我正在努力处理 monads 的函数实例(谁不呢?)。 Monads may depend on the value of the previous monadic computation. Monads 可能取决于之前的 monadic 计算的值。 What does this exactly mean for the function monad?这对函数 monad 到底意味着什么?

When we look at the bare implementations of applicative/monad instances当我们查看 applicative/monad 实例的裸实现时

ap   f g x = f x (g x)
bind f g x = f (g x) x

it seems as if the result of gx constitutes this previous value.似乎gx的结果构成了这个先前的值。 However, I recently stumbled upon the following exmaple:但是,我最近偶然发现了以下示例:

mainA = (\x y z -> (x,y,z)) <$> (2/) <*> (+1) <*> (\x -> x * x)
mainM = (\x -> (\y -> (\z w -> if w == 0 then (0,y,z) else (x,y,z)) =<< (\x -> x * x)) =<< (+1)) =<< (2/)
mainA 0 -- (Infinity,1.0,0.0)
mainM 0 -- (0.0,1.0,0.0)

Since a monadic action has to return a monad we have this additional lambda w -> ... within mainM 's definition.由于 monadic 操作必须返回一个 monad,因此我们在mainM的定义中添加了这个额外的 lambda w -> ... This gives us access to the initial value that is passed to the overall computation.这使我们可以访问传递给整体计算的初始值。 Given bind fgx = f (gx) x , does this mean the previous value for the function instance is x not the result of gx ?给定bind fgx = f (gx) x ,这是否意味着函数实例的先前值是x而不是gx的结果?

Sorry for the confusion!对困惑感到抱歉!

In this one-liner spelling, mainM 's definition is kinda hard to follow, so I'll begin by adding some indentation:在这种单行拼写中, mainM的定义有点难以理解,所以我将首先添加一些缩进:

mainM =
  (\x ->
    (\y -> 
      (\z w -> if w == 0 then (0,y,z) else (x,y,z))
       =<< (\x -> x * x))
    =<< (+1))
  =<< (2/)

Since a monadic action has to return a monad we have this additional lambda w -> ... within mainM 's definition.由于 monadic 操作必须返回一个 monad,因此我们在mainM的定义中添加了这个额外的 lambda w -> ... This gives us access to the initial value that is passed to the overall computation.这使我们可以访问传递给整体计算的初始值。

That's pretty much correct.这是非常正确的。 It might be slightly easier to see what's going on if we don't write that function as a function of two arguments (a function of two arguments is a function of one arguments that returns a function):如果我们不将该函数编写为具有两个参数的函数(具有两个参数的函数是返回一个函数的一个参数的函数),则可能更容易看出发生了什么:

mainM =
  (\x ->
    (\y -> 
      (\z ->
        \w -> if w == 0 then (0,y,z) else (x,y,z))
       =<< (\x -> x * x))
    =<< (+1))
  =<< (2/)

So the results of applying (2/) , (+1) and (\\x -> x * x) to the initial parameter/environment are bound to x , y and z , respectively, and the three of them are used to obtain the final result.所以将(2/) , (+1)(\\x -> x * x)应用于初始参数/环境的结果分别绑定到x , yz ,并使用它们三个来获得最终结果。 If we felt like using w consistently for the environment, the definition would look like this:如果我们想对环境始终使用w ,那么定义将如下所示:

mainM =
  (\x ->
    (\y -> 
      (\z ->
        \w -> if w == 0 then (0,y,z) else (x,y,z))
       =<< \w -> w * w)
    =<< \w -> w + 1)
  =<< \w -> 2 / w

Or, using (>>=) instead of (=<<) :或者,使用(>>=)而不是(=<<)

mainM =
  (\w -> 2 / w) >>= \x ->
  (\w -> w + 1) >>= \y ->
  (\w -> w * w) >>= \z ->
  \w -> if w == 0 then (0,y,z) else (x,y,z)

Or, using do-notation:或者,使用 do-notation:

mainM = do
  x <- \w -> 2 / w
  y <- \w -> w + 1
  z <- \w -> w * w
  \w -> if w == 0 then (0,y,z) else (x,y,z)

In any case, note that mainM isn't actually using the results of the previous computations (that is, x , y and z ) to decide which computation to perform next (that is, which function of the environment to use).在任何情况下,请注意mainM实际上并没有使用先前计算的结果(即xyz )来决定接下来要执行的计算(即使用环境的哪个函数)。 We can actually rewrite it using only applicative:我们实际上可以只使用 applicative 来重写它:

mainA' = (\w x y z -> if w == 0 then (0,y,z) else (x,y,z))
  <*> (2/) <*> (+1) <*> (\x -> x * x)

Using the results of a previous computation to decide on the next one would look more like this:使用先前计算的结果来决定下一个计算结果看起来更像这样:

testM = (\x -> if x == 0 then \_ -> 0 else \w -> w / x) =<< subtract 1
GHCi> testM 0.99
-98.99999999999991
GHCi> testM 1
0.0
GHCi> testM 1.01
100.99999999999991

Still, the function/reader monad isn't a good illustration of the differences between Applicative and Monad , because (<*>) and (=<<) happen to be equivalent for it .尽管如此,函数/读取器 monad 并不能很好地说明ApplicativeMonad之间的差异,因为(<*>)(=<<)恰好与 it 等效 With testM , for instance, we can simply pull the environment argument outside of the if-expression...例如,使用testM ,我们可以简单地将环境参数拉到 if 表达式之外...

testM' = (\x w -> if x == 0 then 0 else w / x) =<< subtract 1

... thus getting something which is straightforward to rewrite using Applicative : ...从而得到一些可以直接使用Applicative重写的东西:

testA = (\w x -> if x == 0 then 0 else w / x) <*> subtract 1

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

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