Monads,>> =和"嵌套的lambdas"

时间:2016-01-09 02:27:42

标签: haskell monads

我认为在阅读Graham Hutton's monad article后我感到困惑。 以下是砖墙。 (文章中的文字)

  

使用>>=,我们的评估者现在可以改写为:

eval (Val n) = Just n
eval (Div x y) = eval x >>= (\n -> eval y >>= (\m -> safediv n m))
     

除法的情况可以理解如下:评估x并调用   其结果值n ,然后评估y并调用其结果值m ,   最后通过应用safediv结合两个结果。

我还没有理解nm中lambda的临时结果是如何存储的。什么是" lambdas嵌套的规则"并重新审视其结果?

编辑:

我接受我是一个新手,我的基础知识并不强烈。理解不好的一个原因是对绑定运算符>>=的定义和结果的混淆。我忽略了绑定运算符将返回计算值

的事实
"f applied on x". 

我会尝试总结一下(半)的理解。

在此上下文中绑定运算符的定义:

(>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b
Nothing  >>=  _  = Nothing
(Just x) >>=  f  = f x

解释上述定义:

签名 - 绑定运算符采用Maybe a的类型,另一个带有签名((a->maybe a)的高阶函数,并将其应用于a并返回结果值输入Maybe b

模式1 - 当Maybe aNothing时,绑定运算符并不关心带有签名(a->maybe a)的函数 - 返回{{ 1}}。

模式2 - 当NothingMaybe a时,绑定运算符关心函数并应用函数ie(Just x,function f xf获取值x,并返回类型为Just x的结果值。

此处Maybe ba可以是不同类型。例如b可以是整数a可以是b

现在,如果我们在给定的除法示例中应用bind的定义,

String
eval (Val n) = Just n eval (Div x y) = eval x >>= (\n -> eval y >>= (\m -> safediv n m)) 中的

eval x将根据 eval (Div x y) 模式返回Just n 。这是绑定运算符的第一个参数。因此我们可以把它写成

eval (Val n) = Just n

因为绑定运算符eval (Div x y) = Maybe a >>= f -- .We are applying `>>=` operator. eval (Div x y) = Just n >>= (\n -> eval y >>= (\m -> safediv n m)) 的结果在我们的上下文中是 >>= ,所以" lambda" f x 将应用于(\n -> eval y >>= (\m -> safediv n m))

请你知道我的理解到目前为止是否正确。 如果这种理解是正确的,我需要弄清楚" lambda"的应用结果。 n 上的 (\n -> eval y >>= (\m -> safediv n m))

n

2 个答案:

答案 0 :(得分:4)

我害怕如果你不理解词法范围和词法闭包的基础知识,那么你将很难理解嵌套lambda中的这种“状态”管理,特别是在desugared monad代码的情况下。

所以你的问题的答案实际上并不在于你所要求的,而是在你的理解中缺少一些先决条件。

考虑

> let f = \x -> \y -> y * 2 + x * 7
> let f' = f 3

现在f'包含类似于闭包的东西 - 它是第一个lambda的主体,其中x的值已被记住为3。依次将值传递给f',也“填充占位符”y,之后记忆的x值和y的现在可用值(按需)用于评估表达式2y + 7x。

> f' 4
29

Monads只是使用这样的结构来记住以前的monadic步骤中的值。当然,通常你会使用隐藏这种lambda管道的do句法糖。

P.S。如果它可能不明显,这两行是等价的:

> let f = \x -> \y -> y * 2 + x * 7
> let f x y = y * 2 + x * 7

我只是使用显式curried形式来绘制与monadic lambdas的平行线。

答案 1 :(得分:1)

我不太清楚我理解你的问题。 "临时结果"例如eval x成为n,而临时结果为#34}。 eval y成为m。对于safediv n m,范围内都可以访问nm,因此您可以引用它们,就像您可以引用您所在范围内的任何变量一样,例如嵌套let表达式时。

请注意,价值(例如n)是"递交"通过(\n -> ...)的绑定(>>=)定义(即Maybe)到lambda (>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b。例如,expr x评估为Maybe a,然后将其应用于>>=,例如themaybe >>= lambda。在下面的定义中,lambda对应于f,因此您可以看到,如果eval x评估为Just a,它会将x应用于f x lambda(即Maybe a)。 lambda本身的计算结果为>>= lambda,这就是为什么你可以进一步链接/嵌套另一个 (>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b m >>= f = case m of Nothing -> Nothing Just x -> f x

 1=New York, 2=Paris, 3=London, 4=Moscow, 5=Boston, ..., 230=Tblisi