Haskell 这个表达式是如何工作的?

Haskell 这个表达式是如何工作的?,haskell,lambda,anonymous-function,let,expression-evaluation,Haskell,Lambda,Anonymous Function,Let,Expression Evaluation,考虑到这行Haskell代码,我的任务是将其评估为最简单的形式 let g h k = (\x -> k (h x)) in g (+1) (\x -> x+x) 20 我已经得到了答案(当然我自己也在GHCI中进行了评估):42 但是,我想更好地了解评估在这里是如何实际工作的。总的来说,我想我知道(简单)如何让表达式工作: 范例 a = let y = 5 in y * 5 -- a == 25 这计算为25,因为我们将y绑定到5的值,并且a被分配到y*5的值(在中后面的部分

考虑到这行Haskell代码,我的任务是将其评估为最简单的形式

let g h k = (\x -> k (h x)) in g (+1) (\x -> x+x) 20
我已经得到了答案(当然我自己也在GHCI中进行了评估):
42

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

范例

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

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

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

  • 20
    是产生
    k(h20)
  • h20
    给出
    20+1
    =
    21
  • k(h20)
    =
    k21
    =
    21+21
    =
    42

但让我困惑的是在let之后使用了
ghk
。这是什么意思?

ghk=…
是一个函数定义。这意味着将
g
应用到两个参数(名为
h
k
)的结果将计算到
部分。换句话说,它是
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

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

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

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

或:

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

因此,使用
let
表达式,我们定义了一个类似于上面定义的局部作用域函数。现在,如果我们调用
g(+1)(\x->x+x)20
,那么将使用
h=(+1)
k=(\x->x+x)
x=20
调用
g

因此,我们将其评估为:

(\x -> x+x) ((+1) 20)
评估结果如下:

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

不,
g
g=\hkx->k(hx)
左边的变量也是参数。函数头和lambda表达式之间的变量传递是否有一个术语?如果可能的话,我想通过阅读更多关于它的内容来更好地理解它。@unnicolo它只是语法上的糖
fx=x
已被删除为
f=\x->x
。所有函数最终都是通过将名称绑定到lambda表达式来定义的,将参数从lambda表达式移动到绑定的左侧只是一种更轻量级的语法。
(\x -> x+x) ((+1) 20)
   (\x -> x+x) ((+1) 20)
-> ((+1) 20)+((+1) 20)
-> 21 + 21
-> 42