对 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>

lambdalet的唯一区别是let立即赋值给x,而lambda等待该值作为参数.

因此,如果您想用 lambda 直接分配的值包装 <body>,您只需传递该值即可!

((lambda (x) <body>) 42)

这使得它完全等同于:

(let ((x 42)) <body>)