Closures

Started by cormullion, October 26, 2007, 05:12:45 AM

Previous topic - Next topic

cormullion

What's the difference between newLISP closures and Lisp/Scheme closures? I've been reading http://lispy.wordpress.com/2007/10/25/what-you-dont-know-about-closures-can-hurt-you/">//http://lispy.wordpress.com/2007/10/25/what-you-dont-know-about-closures-can-hurt-you/:


QuoteSo 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:


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

Jeff

#1
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:


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


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

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

=====

Old programmers don\'t die. They just parse on...



http://artfulcode.net\">Artful code

cormullion

#2
Right - so the article's description of closure being just 'a procedure with state' is not the whole story...

Jeff

#3
Well, it is a procedure with state, but that doesn't explain how that state is kept.
Jeff

=====

Old programmers don\'t die. They just parse on...



http://artfulcode.net\">Artful code