Scheme / Racket闭包的目的是什么?

时间:2017-03-25 19:44:53

标签: scheme closures racket

我正在学习Scheme并刚刚遇到了Closures。提供了以下示例,演示了闭包的使用:

(define (create-closure x)
    (lambda () x))

(define val (create-closure 10))

根据我的理解,在评估上述代码时,val将等于10。我意识到这只是一个例子,但我不明白封闭是如何有用的。有什么优势以及需要这样一个概念的场景是什么?

5 个答案:

答案 0 :(得分:2)

val不是10,而是关闭。如果您将其称为(val),则会返回x的值。 x是一个仍然存在的闭包变量,因为它仍然在使用中。一个更好的例子是:

(define (larger-than-predicate n)
  (lambda (v) (> v n )))

(filter (larger-than-predicate 5) '(1 2 3 4 5 6 7 8 9 10))
; ==> (6 7 8 9 10)

因此谓词将参数与v进行比较,5是一个仍然保留n的变量。在动态绑定的lisp中,这是不可能的,因为在发生比较时var将不存在。

在Algol和Scheme中引入了Lecical范围。 JavaScript,PHP和C#都是algol方言,并从那里继承了它。 Scheme是获得它的第一个lisp,紧随其后的是Common Lisp。它实际上是最常见的范围。

答案 1 :(得分:2)

从此示例中,您可以看到闭包允许函数本地环境在调用后保持可访问性。

(define count
   (let ((next 0))
     (lambda ()
       (let ((v next))
         (set! next (+ next 1))
         v))))
(count)
(count) 
(count)
0..1..2

答案 2 :(得分:1)

  1. 我相信你给出的例子,val不会等于10,而是将一个lambda对象(lambda () 10)分配给val。所以(val)等于10。

  2. 在Scheme的世界中,有两个不同的概念共享相同的术语“闭包”。有关这两个术语的简要介绍,请参阅this post。在你的情况下,我相信“封闭”你的意思是“词汇封闭”。在您的代码示例中,参数x是返回的lambda的free variable,并由返回的lambda引用,因此保持词法闭包以存储x的值。我相信this post会给你一个很好的解释(词汇)闭包。

答案 3 :(得分:1)

顺便说一句,您的问题中的create-closureCombinator Birds族的某些人称为 Kestrel 组合器。它在Church encoding中也称为 True ,它使用lambda(闭包)对布尔值(以及其他所有值)进行编码。

(define (kestrel a)
  (lambda (b) a))

(define (create-list size proc)
  (let loop ((x 0))
    (if (= x size)
        empty
        (cons (proc x)
              (loop (add1 x))))))


(create-list 5 identity)
; '(0 1 2 3 4)

(create-list 5 (kestrel 'a))
; '(a a a a a)

在球拍中(我不确定Scheme),该过程称为const-

(create-list 5 (const 'a))
; '(a a a a a)

答案 4 :(得分:0)

完全赞同黄丽芙的回答。

此外,我想强调最明显的闭包使用,即回调。

例如,在JavaScript中,我可能会写

function setup(){
  var presses = 0;
  function handleKeyPress(evt){
    presses = presses + 1;
    return mainHandler(evt);
  }
  installKeyHandler(handleKeyPress);
}

在这种情况下,对我来说重要的是我作为密钥处理程序安装的函数“知道”presses变量的绑定。该绑定存储在闭包中。换句话说,该函数“关闭”presses的绑定。

在JS中几乎每个http GET或POST调用都会发生类似的事情。它也出现在许多其他地方。