What is the purpose of Closures in Scheme/Racket?
Asked Answered
S

5

7

I am learning Scheme and just came across Closures. The following example provided, demonstrating the use of Closures:

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

(define val (create-closure 10))

From what I understand, when the above code is evaluated, val will equal to 10. I realize this is just an example, but I don't understand just how a closure would be helpful. What are the advantages and what would a scenario where such a concept would be needed?

Spital answered 25/3, 2017 at 19:44 Comment(0)
L
4

val is not 10 but a closure. If you call it like (val) it returns the value of x. x is a closure variable that still exists since it's still in use. A better example is this:

(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)

So the predicate compares the argument with v which is a variable that still holds 5. In a dynamic bound lisp this is not possible to do because n will not exist when the comparison happens.

Lecical scoping was introduces in Algol and Scheme. JavaScript, PHP amd C# are all algol dialects and have inherited it from there. Scheme was the first lisp to get it and Common Lisp followed. It's actually the most common scoping.

Lucila answered 25/3, 2017 at 20:16 Comment(0)
S
4

From this example you can see that the closure allows the functions local environment to remain accessible after being called.

(define count
   (let ((next 0))
     (lambda ()
       (let ((v next))
         (set! next (+ next 1))
         v))))
(count)
(count) 
(count)
0..1..2
Scifi answered 30/6, 2019 at 7:5 Comment(0)
C
3
  1. I believe in the example you give, val will NOT equal to 10, instead, a lambda object (lambda () 10) will be assigned to val. So (val) equals to 10.

  2. In the world of Scheme, there are two different concepts sharing the same term "closure". See this post for a brief introduction to both of these terms. In your case, I believe by "closure" you mean "lexical closure". In your code example, the parameter x is a free variable to the returned lambda and is referred to by that returned lambda, so a lexical closure is kept to store the value of x. I believe this post will give you a good explanation on what (lexical) closure is.

Caltanissetta answered 25/3, 2017 at 20:3 Comment(0)
D
1

Totally agree with Lifu Huang's answer.

In addition, I'd like to highlight the most obvious use of closures, namely callbacks.

For instance, in JavaScript, I might write

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

In this case, it's important to me that the function that I'm installing as the key handler "knows about" the binding for the presses variable. That binding is stored in the closure. Put differently, the function is "closed over" the binding for presses.

Similar things occur in nearly every http GET or POST call made in JS. It crops up in many many other places as well.

Delayedaction answered 25/3, 2017 at 20:14 Comment(0)
I
1

Btw, create-closure from your question is known by some as the Kestrel combinator, from the family of Combinator Birds. It is also known as True in Church encoding, which encodes booleans (and everything else) using lambdas (closures).

(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)

In Racket (I'm unsure about Scheme), this procedure is known as const -

(create-list 5 (const 'a))
; '(a a a a a)
Illlooking answered 1/7, 2019 at 16:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.