Page 1 of 1

Closures

Posted: Fri Oct 26, 2007 12:12 pm
by cormullion
What's the difference between newLISP closures and Lisp/Scheme closures? I've been reading http://lispy.wordpress.com/2007/10/25/w ... -hurt-you/:
So a closure turns out to be just a procedure with state.
The 'classic example' of the accumulator built-in to a function that he mentions has appeared on this forum too:

Code: Select all

(context 'gen) 

(define (foo) 
    (if (number? acc) 
        (inc 'acc) 
        (set 'acc 0))) 

(context MAIN) 

> (gen:foo) 
0
> (gen:foo) 
1 
> (gen:foo) 
2 
> (gen:foo) 
3 
Although this looks like a procedure with state, I know that Lutz has said that newLISP 'context closures' aren't closures...

So, what's the difference between newLISP 'closures' and Lisp/Scheme closures?

Posted: Fri Oct 26, 2007 12:40 pm
by Jeff
Closures are a feature of lexical scoping and dynamic function definition. For example, if you create a lambda inside another function, variables that are in the outer scope must be preserved for that lambda. When that lambda is later called, those variables that would have been available inside of the scope it was defined in are then activated in the current call's scope.

newLisp is dynamically scoped. Any time a function is called, it is called within the current scope, not the scope it was defined in.

newLisp has contexts, however, which are lexical namespaces that can simulate closures. You can do that with a functor (a function with the same name as its context, like foo:foo). The context preserves the symbols in the functor's scope, and they are available when the function is called later, no matter where it is called from.

However, the big difference is that within a context, dynamic scoping rules still apply. It is not a lexical scope. It is a lexically defined namespace that is parallel to the MAIN, dynamic scope. So:

Code: Select all

(setq foo:x "Hello world")
(define (foo:foo) (lambda () (println x)))
(setq x "Hello Corm")
(setq my-foo (foo:foo))
(my-foo) ; => prints "Hello Corm"
In Scheme, it would work like this:

Code: Select all

(define foo
  (lambda ()
    (let ((x "Hello world"))
      (lambda () (print x)))))

(define my-foo (foo))
(define x "Hello Corm")
(my-foo) ; => prints "Hello world"

Posted: Fri Oct 26, 2007 2:18 pm
by cormullion
Right - so the article's description of closure being just 'a procedure with state' is not the whole story...

Posted: Fri Oct 26, 2007 2:44 pm
by Jeff
Well, it is a procedure with state, but that doesn't explain how that state is kept.