DemCodeLines
DemCodeLines

Reputation: 1920

What is the purpose of Closures in Scheme/Racket?

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?

Upvotes: 7

Views: 7868

Answers (5)

Mulan
Mulan

Reputation: 135227

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)

Upvotes: 1

Robert Hale
Robert Hale

Reputation: 41

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

Upvotes: 4

Lifu Huang
Lifu Huang

Reputation: 12788

  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.

Upvotes: 3

Sylwester
Sylwester

Reputation: 48745

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.

Upvotes: 4

John Clements
John Clements

Reputation: 17203

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.

Upvotes: 1

Related Questions