Haskell 这个表达式是如何工作的?
考虑到这行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的值(在中后面的部分
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