Misunderstanding about closures

Alexander Schmolck a.schmolck at gmx.net
Sat Jun 12 23:50:35 CEST 2004


Jacek Generowicz <jacek.generowicz at cern.ch> writes:

> Alexander Schmolck <a.schmolck at gmx.net> writes:
>
>> Not quite. In fact in the language that more or less started it all,
>> scheme, the standard iteration construct 'do' does indeed introduce
>> a *new binding* on each iteration.
>
> Yes, but this is a consequence of Scheme faking iteration with
> recursion.

Why "faking"? How is this CL-style do below inferior to the real thing (apart
from the fact that it's possibly inelgant or broken because it's quickly
hacked together by someone of limited competence as a scheme programmer:)?

;; cl-style do (with mandatory step clause, to make the code a bit more
;; compact)
(define-syntax cl-style-do
  (syntax-rules  ()
    ;; this...
    [(cl-style-do ((var init step) ...) (end-test result ...) body ...)
     ;; ... gets rewritten as
     (let ((var init) ...) ; normal let; similar to var = init; ...
        (let loop ()  ; named let: like def loop(): ...; loop()
          (if end-test
              (begin
                (if #f #f)  ; trick to get void return value if no result form
                result ...) ; is given
              (begin body ...
                     (set! var step) ...
                     (loop)))))]
    ))

;; for comparison, this is a (again slightly simplified) scheme style do
(define-syntax scheme-style-do
  (syntax-rules  ()
    ;; this...
    [(scheme-style-do ((var init step) ...) (end-test result ...) body ...)
     ;; ... gets rewritten as
     (let loop ((var init) ...) ; like def loop(var...): ...; loop(init...)
       (if end-test
           (begin
             (if #f #f)
             result ...)
           (begin body ...
                  (loop step ...))))]
     ))


Recycling the contorted pythonesque scheme example I posted earlier:

(define l '())                       ; an empty list

(cl-style-do ((x 0 (+ 1 x)))         ; start x with 0, then add 1 at each step
    ((= x 10))                       ; stop when x is 10
  (set! l (cons (lambda () x) l)))        ; add a new function closing over x to
				     ; the *front* of l

(set! l (reverse l))                 ; since we added to the front we 
                                     ; have to reverse l

((list-ref l 3))                     ; get list element 3 and execute it

=> 10                                (same as in CL; not 3 as with standard do)


>> Common Lisp OTOH doesn't -- like python:
>
> If you used recursion-based iteration constructs in either of these
> languages, the same would happen.
>
> Future Googlers please refer to:
>
>    http://www.google.com/groups?as_umsgid=tyfsmgtbewl.fsf%40lxplus030.cern.ch

Again you seem to imply that somehow scheme does something inappropriate
and/or is somehow limiting compared to CL/python style iteration -- whereas
AFAICT the exact opposite applies.

I can't see how the new bindings that scheme's do introduces on each iteration
step matter unless you create a closure in the body of the do loop and in that
case chances are scheme's behavior is *precisely* what you want. And if, for
some (obscure ?) reason, CL style do is what you need then I think you can
trivially implement it as above.

OTOH, if you want scheme style tail recursion (which makes it feasible to
express some problems significantly simpler and quite a few more lucidly than
if you had to use plain iteration) in (standard) CL or python you're pretty
screwed -- you can to some extent fake it in CL, but even that requires a lot
of work. For python you'd have to write a compiler to standard python (or
bytecode).

'as



More information about the Python-list mailing list