Today I did a little more work on my slides for the MUG presentation, but I also read some more of the (excellent) manual. The section on Closures really helped me understand better what was going on.
For those playing along at home, a closure is when a function is called in such a way that the local state is preserved. So, for example:
(define (silly-function x)
(let ((y (/ x 2)))
y))
This defines a lexical scope for y where y does not exist outside of the scope of the function. If I did the following:
(define y "moo")
(silly-function 8) => 4
y => "moo"
"y" is not overwritten.
What makes closure so powerful is best described in this example (taken from the Guile documentation):
(define (make-serial-number-generator)
(let ((current-serial-number 0))
(lambda ()
(set! current-serial-number (+ current-serial-number 1))
current-serial-number)))
(define entry-sn-generator (make-serial-number-generator))
(entry-sn-generator) => 1
(entry-sn-generator) => 2
...
In this case current-serial-number
is initialized with 0 and the lambda function turns the function into a variable. Since the function as a whole is saved as a variable you can assign it to another variable and that variable holds the address of the instantiated function. So when you call that variable as a function it looks up the address of the function, brings up the current state of where it left off, and then (in this case) increments the value of current-serial-number.
Simple, no?
I'm pretty sure I'm not explaining this right, but I'll hopefully explain it better for the slides. Closure is one of the important concepts of JavaScript and it's nice to see a clear example of this in Scheme.
Onward!