我正在学习Scheme并刚刚遇到了Closures。提供了以下示例,演示了闭包的使用:
(define (create-closure x)
(lambda () x))
(define val (create-closure 10))
根据我的理解,在评估上述代码时,val
将等于10
。我意识到这只是一个例子,但我不明白封闭是如何有用的。有什么优势以及需要这样一个概念的场景是什么?
答案 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)
我相信你给出的例子,val不会等于10,而是将一个lambda对象(lambda () 10)
分配给val。所以(val)
等于10。
在Scheme的世界中,有两个不同的概念共享相同的术语“闭包”。有关这两个术语的简要介绍,请参阅this post。在你的情况下,我相信“封闭”你的意思是“词汇封闭”。在您的代码示例中,参数x
是返回的lambda的free variable,并由返回的lambda引用,因此保持词法闭包以存储x的值。我相信this post会给你一个很好的解释(词汇)闭包。
答案 3 :(得分:1)
顺便说一句,您的问题中的create-closure
被Combinator 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调用都会发生类似的事情。它也出现在许多其他地方。