[comp.lang.lisp] Downward Funargs no longer anonymous?

norvig@bansai.uucp (Peter Norvig) (07/12/90)

In several LISPM implementations, we have been able to declare:

#'(lambda (x)
    (declare (sys:downward-function))
    (f x y))

to indicate that even though the lambda expression captures the variable y
from the environment, it will only be used by functions below, and hence can
be stack-allocated, without copying the enviornment.

In CLtL2, the declaration DYNAMIC-EXTENT has been added, ostensibly to cover
this and other cases.  Unfortunately, this means we can no longer use
anonymous lambda expressions.  I have to say instead:

(flet ((f (lambda (x)
            (declare (dynamic-extent f))
            (f x y))))
   ...
   #'f
   ...
   )

where the "..." indicate the surrounding environment.  Thus, the
dynamic-extent declaration does not seem to do the job of
sys:downward-function very well.  Was this problem discussed
when dynamic-extent was adopted?

masinter@parc.xerox.com (Larry Masinter) (07/12/90)

In article <26081@pasteur.Berkeley.EDU> norvig@bansai.uucp (Peter Norvig) writes:

>   In several LISPM implementations, we have been able to declare:

>   #'(lambda (x)
>       (declare (sys:downward-function))
>       (f x y))

>   to indicate that even though the lambda expression captures the variable y
>   from the environment, it will only be used by functions below, and hence can
>   be stack-allocated, without copying the enviornment.

>   In CLtL2, the declaration DYNAMIC-EXTENT has been added, ostensibly to cover
>   this and other cases.  Unfortunately, this means we can no longer use
>   anonymous lambda expressions.  I have to say instead:

>   (flet ((f (lambda (x)
>	       (declare (dynamic-extent f))
>	       (f x y))))
>      ...
>      #'f
>      ...
>      )

>   where the "..." indicate the surrounding environment.  Thus, the
>   dynamic-extent declaration does not seem to do the job of
>   sys:downward-function very well.  Was this problem discussed
>   when dynamic-extent was adopted?

Well, it was discussed.
================================================================
Begin excerpts  (David Moon, replying to Sandra Loosemore...)
================================================================
Date: Fri, 26 May 89 12:22 EDT
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Subject: Re: issue DYNAMIC-EXTENT-FUNCTION, version 1

...

    Date: Fri, 26 May 89 09:42:51 MDT
    From: sandra%defun@cs.utah.edu (Sandra J Loosemore)

...


    I don't know what to do about the related issue of declaring that an
    anonymous lambda has dynamic extent -- none of the alternatives that
    have come up so far have much appeal.  Anyway, I don't think this
    problem is as critical, because you could just restructure the program
    to give the function a name.

Do you mean something like:

(defmacro dynamic-extent-lambda (lambda-list &body body)
  `(flet ((dummy-name ,lambda-list ,@body))
     (declare (dynamic-extent dummy-name))
     #'dummy-name))

The problem with this is that the scope of the dynamic-extent declaration
is too small, in fact, so small that this is an erroneous program.  That
shows something interesting about the Symbolics sys:downward-function
declaration: the scope that defines the dynamic extent is larger than
the lambda-expression containing the declaration.  Implementationally it's
the surrounding function definition, semantically it would be enough for it
to be the surrounding form.  I guess you're going to require that

  (funcall <foo> (lambda (...) (declare (sys:downward-function)) ...))

be restructured as

  (flet ((dummy (...) ...))
    (declare (dynamic-extent #'dummy))
    (funcall <foo> #'dummy))

which is okay except that it's hard to see how to define a macro that
gives it back a nice non-obtrusive syntax.  Maybe

  (call-with-dynamic-functions
    (funcall <foo> #'(lambda (...) ...)))

Where the call-with-dynamic-functions macro pulls apart its subform
looking for lambda expressions.  The macro doesn't need to be in the
standard, programming stylists can define it for themselves.  It's
still more obtrusive than something inside the lambda, though.

    I think you'd also get the right effect
    by declaring that all the closed-over variables and functions
    referenced in the lambda have dynamic extent.  

I don't think that would mean the same thing.  After all, in this example

  (let ((a <foo>))
    (declare (dynamic-extent a))
    (<bar> #'(lambda (z) (if (<baz> z) (<frob> a) (<borf> z)))))

the dynamic extent declaration for A might mean that by the time the
scope of the declaration is exited, something will happen that will
make <baz> return false from then on, so A will no longer be referenced,
even though the closure that was given as an argument to <bar> will
continue to be called.  You are correct that the environment of the
closure could be discarded, but I don't see how the closure itself
could be discarded; it would have to have indefinite extent.

    So, I don't plan on doing anything about it.

I guess that's probably for the best.

--
Larry Masinter (masinter@parc.xerox.com)
Xerox Palo Alto Research Center (PARC)
3333 Coyote Hill Road; Palo Alto, CA USA 94304
Fax: (415) 494-4333