Subject: Re: Calling a function with your &rest
From: rpw3@rigden.engr.sgi.com (Rob Warnock)
Date: 1998/10/29
Newsgroups: comp.lang.lisp
Message-ID: <719nqg$1cdpn@fido.engr.sgi.com>
Kent M Pitman  <pitman@world.std.com> wrote:
+---------------
| This relates to my beef about tail recursion in Scheme, which I think
| is a fine new way of looking at an old idea that offers interesting
| leverage, but that should not be thought of as a replacement for
| the old idea of iterating, which has its own power in terms of being
| a simpler formulation for the set of simple cases where the more
| complex formulation is not needed.
+---------------

[And at the risk of getting flamed for it,] I'll say again that one of
the additional dangers in talking about tail-recursion as "the Scheme
way of iterating" is that the storage & variable-binding behaviors of
Scheme "iteration" -- as it is conventionally coded [with the state held
in bound variables in a "do" or "(let loop...)" or explicit self-tail-call
parameters] -- and Common Lisp iterative constructs are not the same,
either. For example, in Scheme's "do" each trip around the loop binds
the variables to *fresh* locations, which are then initialized with
the "step" values, while in Common Lisp's "do" the *same* bindings are
*assigned* to ("as with psetq", sez the HyperSpec) with the "step" values. 

Not only can this lead to very different allocation patterns and garbage
collector behavior (as I think I mentioned before in this thread), but
also to very different results!!  Consider this somewhat contrived example
[actually run on several Schemes and on CLISP, just to be sure! ;-} ]:

    === Scheme ===                      === Common Lisp ===
    > (define (foo)                     > (defun foo ()
	(do ((i 0 (+ 1 i))                  (do ((i 0 (+ 1 i))
	     (j (lambda () 'first)               (j (lambda () 'first)
		(lambda () i))                      (lambda () i))
	     (k '() (cons j k)))                 (k '() (cons j k)))
	    ((> i 3) (reverse k))))             ((> i 3) (reverse k))))
					FOO
    > (map (lambda (x) (x)) (foo))      > (mapcar #'funcall (foo))
    (first 0 1 2)                       (FIRST 4 4 4)
    >                                   >

The "foo"s are IDENTICAL (well, define/defun syntax), yet the results
certainly aren't!


-Rob

p.s. You *can*, of course, write a "do" loop in Scheme that gives CL-like
semantics for this example, but you have to go to more trouble:

    > (define (foo2)
        (let ((shared-i 'ignored)) 
          (do ((i 0 (+ 1 i))
               (j (lambda () 'first) 
                  (lambda () shared-i)) 
               (k '() (cons j k)))  
              ((> i 3) (set! shared-i i) (reverse k))
            (set! shared-i i))))
    > (map (lambda (x) (x)) (foo2))
    (first 4 4 4)
    > 

[And, yes, I know, the second "set!" is not necessary... in *this* example...]

-----
Rob Warnock, 8L-855		rpw3@sgi.com
Applied Networking		http://reality.sgi.com/rpw3/
Silicon Graphics, Inc.		Phone: 650-933-1673
2011 N. Shoreline Blvd.		FAX: 650-964-0811
Mountain View, CA  94043	PP-ASEL-IA