对 let 到 lambda 的转换感到困惑
Confused by let to lambda conversion
我目前正在经历这个 great article on Y-combinator by Mike Vanier。在解释中删除了以下行:
It turns out that any let expression can be converted into an equivalent lambda expression using this equation:
(let ((x <expr1>)) <expr2>)
==> ((lambda (x) <expr2>) <expr1>)
文章通过转换说明了这一说法:
(define (part-factorial self)
(let ((f (self self)))
(lambda (n)
(if (= n 0)
1
(* n (f (- n 1)))))))
至:
(define (part-factorial self)
((lambda (f)
(lambda (n)
(if (= n 0)
1
(* n (f (- n 1))))))
(self self)))
现在,我明白了上面两个代码片段如何以及为什么相同,尽管我无法理解将 let
转换为 lambda
的一般方程式是:
(let ((x <expr1>)) <expr2>)
==> ((lambda (x) <expr2>) <expr1>)
非常感谢详尽的解释。
最后我自己弄明白了 =)。
我遗漏的一点是:
(let ((x <expr1>)) <expr2>)
==> ((lambda (x) <expr2>) <expr1>)
x
存在于 <expr2>
内的某处,所以它更像是:
(let ((x <expr1>)) <expr-containing-x>)
==> ((lambda (x) <expr-containing-x>) <expr1>)
话虽如此,如果我们将 x
替换为 f
,则:
(define (part-factorial self)
(let ((f (self self)))
(lambda (n)
(if (= n 0)
1
(* n (f (- n 1)))))))
以及在:
(define (part-factorial self)
((lambda (f)
(lambda (n)
(if (= n 0)
1
(* n (f (- n 1))))))
(self self)))
并且会用不同的颜色高亮显示x
、<expr1>
和<expr2>
,这样转换公式就清楚了:
您应该想象一下有一种非常小的 lisp 语言,它有 lambda
但没有 let
。你想做的事:
(let ((nsq (square n)))
(+ nsq nsq))
你知道 nsq
是一个新变量并且 let
的主体可以成为一个函数:
(lambda (nsq) (+ nsq nsq))
然后你需要使用它来获得相同的值:
((lambda (nsq) (+ nsq nsq)) (square n))
假设您的简单方案具有宏,因此您实现为 let
:
(define-syntax let
(syntax-rules ()
[(let ((binding value) ...)
body ...)
((lambda (binding ...)
body ...)
value ...)]))
请注意,在许多实现中,这实际上正是以这种方式发生的。
let
让您打开一个变量可用的新环境。在编程语言术语中,我们说它 "opens a new frame".
当您编写 (let ((x 42)) <body>)
时,您创建了一个框架,其中 x
在 <body>
中可用,并为其分配值 42
.
好吧,还有另一个工具可以让您打开新的框架。事实上,它通常是您可以用来构建更多抽象结构的基本积木:它被称为 lambda
.
lambda
打开一个新框架,其中的参数可用于其主体。
当您编写 (lambda (x) <body>)
时,您使 x
可用于函数的 <body>
。
lambda
和let
的唯一区别是let
立即赋值给x
,而lambda
等待该值作为参数.
因此,如果您想用 lambda
直接分配的值包装 <body>
,您只需传递该值即可!
((lambda (x) <body>) 42)
这使得它完全等同于:
(let ((x 42)) <body>)
我目前正在经历这个 great article on Y-combinator by Mike Vanier。在解释中删除了以下行:
It turns out that any let expression can be converted into an equivalent lambda expression using this equation:
(let ((x <expr1>)) <expr2>) ==> ((lambda (x) <expr2>) <expr1>)
文章通过转换说明了这一说法:
(define (part-factorial self)
(let ((f (self self)))
(lambda (n)
(if (= n 0)
1
(* n (f (- n 1)))))))
至:
(define (part-factorial self)
((lambda (f)
(lambda (n)
(if (= n 0)
1
(* n (f (- n 1))))))
(self self)))
现在,我明白了上面两个代码片段如何以及为什么相同,尽管我无法理解将 let
转换为 lambda
的一般方程式是:
(let ((x <expr1>)) <expr2>)
==> ((lambda (x) <expr2>) <expr1>)
非常感谢详尽的解释。
最后我自己弄明白了 =)。
我遗漏的一点是:
(let ((x <expr1>)) <expr2>)
==> ((lambda (x) <expr2>) <expr1>)
x
存在于 <expr2>
内的某处,所以它更像是:
(let ((x <expr1>)) <expr-containing-x>)
==> ((lambda (x) <expr-containing-x>) <expr1>)
话虽如此,如果我们将 x
替换为 f
,则:
(define (part-factorial self)
(let ((f (self self)))
(lambda (n)
(if (= n 0)
1
(* n (f (- n 1)))))))
以及在:
(define (part-factorial self)
((lambda (f)
(lambda (n)
(if (= n 0)
1
(* n (f (- n 1))))))
(self self)))
并且会用不同的颜色高亮显示x
、<expr1>
和<expr2>
,这样转换公式就清楚了:
您应该想象一下有一种非常小的 lisp 语言,它有 lambda
但没有 let
。你想做的事:
(let ((nsq (square n)))
(+ nsq nsq))
你知道 nsq
是一个新变量并且 let
的主体可以成为一个函数:
(lambda (nsq) (+ nsq nsq))
然后你需要使用它来获得相同的值:
((lambda (nsq) (+ nsq nsq)) (square n))
假设您的简单方案具有宏,因此您实现为 let
:
(define-syntax let
(syntax-rules ()
[(let ((binding value) ...)
body ...)
((lambda (binding ...)
body ...)
value ...)]))
请注意,在许多实现中,这实际上正是以这种方式发生的。
let
让您打开一个变量可用的新环境。在编程语言术语中,我们说它 "opens a new frame".
当您编写 (let ((x 42)) <body>)
时,您创建了一个框架,其中 x
在 <body>
中可用,并为其分配值 42
.
好吧,还有另一个工具可以让您打开新的框架。事实上,它通常是您可以用来构建更多抽象结构的基本积木:它被称为 lambda
.
lambda
打开一个新框架,其中的参数可用于其主体。
当您编写 (lambda (x) <body>)
时,您使 x
可用于函数的 <body>
。
lambda
和let
的唯一区别是let
立即赋值给x
,而lambda
等待该值作为参数.
因此,如果您想用 lambda
直接分配的值包装 <body>
,您只需传递该值即可!
((lambda (x) <body>) 42)
这使得它完全等同于:
(let ((x 42)) <body>)