【问题标题】:How does this let expression work?这让表达式如何工作?
【发布时间】:2018-06-28 20:47:49
【问题描述】:

鉴于这行 Haskell 代码,我的任务是将其评估为最简单的形式。

let g h k = (\x -> k (h x)) in g (+1) (\x -> x+x) 20

我已经得到了答案(当然,我自己也在 GHCI 中对其进行了评估):42

但是,我想更好地了解评估在此处的实际运作方式。总的来说,我想我知道(简单) let 表达式是如何工作的:

例子

a = let y = 5 in y * 5  -- a == 25

计算结果为25,因为我们将y 绑定到5 的值,并且a 被分配给y*5 的值(in 之后的部分)。绑定y = 5只在let范围内有效。

到目前为止,唯一的解释(至少计算为 42)如下:

let g h k = (\x -> k (h x)) in g (+1) (\x -> x+x) 20
  • g(\x -> k (h x))
  • h(+1)(函数(\x -> x+1)
  • k(\x -> x+x)

    1. 20g 的输入,产生 k (h 20)
    2. h 2020 + 1 = 21
    3. k (h 20) = k 21 = 21 + 21 = 42

但让我感到困惑的是在 let 之后使用g h k。这是什么意思?

【问题讨论】:

标签: haskell lambda anonymous-function let expression-evaluation


【解决方案1】:

考虑一个函数定义。如果你写:

g h k x = k (h x)

然后是一个函数,接受三个参数hkx并返回k (h x)。这相当于:

g h k = \x -> k (h x)

或:

g h = \k x -> k (h x)

或:

g = \h k x -> k (h x)

所以我们可以在函数的头部和函数体中的 lambda 表达式之间传递变量。事实上,Haskell 编译器会重写它。

因此,使用let 表达式,我们定义了一个本地范围的函数,就像上面定义的那样。现在,如果我们调用g (+1) (\x -> x+x) 20,那么将因此调用gh = (+1)k = (\x -> x+x)x = 20

所以我们将它评估为:

(\x -> x+x) ((+1) 20)

计算结果为:

   (\x -> x+x) ((+1) 20)
-> ((+1) 20)+((+1) 20)
-> 21 + 21
-> 42

【讨论】:

  • 函数头部和 lambda 表达式之间的这种变量转移是否有一个术语?如果可能的话,我想通过阅读更多内容来更好地理解它。
  • @unnicolo 这只是语法糖。 f x = x 脱糖为 f = \x -> x。所有函数最终都是通过将名称绑定到 lambda 表达式来定义的,将参数从 lambda 表达式移动到绑定的左侧只是一种更轻量级的语法。
【解决方案2】:

g h k = ... 是一个函数定义。这意味着将g 应用于两个参数(名为hk)的结果将评估为... 部分。换句话说,它是g = \h -> \k -> ... 的快捷方式。

所以我们可以逐步简化表达式如下:

let g h k = (\x -> k (h x)) in g (+1) (\x -> x+x) 20
let g = \h -> \k -> (\x -> k (h x)) in g (+1) (\x -> x+x) 20
(\h -> \k -> (\x -> k (h x))) (+1) (\x -> x+x) 20
(\k -> (\x -> k ((+1) x))) (\x -> x+x) 20
(\x -> (\x -> x+x) ((+1) x)) 20
(\x -> x+x) ((+1) 20)
(\x -> x+x) 21
21 + 21
42

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-07-22
    • 1970-01-01
    • 2018-04-03
    • 2011-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多