【问题标题】:What is the purpose of Closures in Scheme/Racket?Scheme/Racket 中闭包的目的是什么?
【发布时间】:2017-08-18 16:03:21
【问题描述】:

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

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

(define val (create-closure 10))

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

【问题讨论】:

    标签: scheme closures racket


    【解决方案1】:

    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 进行比较,v 是一个仍然包含5 的变量。在动态绑定 lisp 中这是不可能的,因为当比较发生时n 将不存在。

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

    【讨论】:

      【解决方案2】:

      从这个例子中你可以看到闭包允许函数本地环境在被调用后仍然可以访问。

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

      【讨论】:

        【解决方案3】:
        1. 我相信在你给出的例子中,val 不会等于 10,相反,一个 lambda 对象(lambda () 10) 将被分配给 val。所以(val) 等于 10。

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

        【讨论】:

          【解决方案4】:

          完全同意黄立夫的回答。

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

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

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

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

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

          【讨论】:

            【解决方案5】:

            顺便说一句,您的问题中的create-closure 被某些人称为Kestrel 组合子,来自Combinator Birds 家族。它在 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)
            

            在 Racket(我不确定 Scheme)中,此过程称为 const -

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

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2015-08-09
              • 2012-04-19
              • 2012-11-23
              • 2018-11-10
              • 2014-03-08
              • 2011-07-10
              • 2012-10-24
              • 2012-06-28
              相关资源
              最近更新 更多