[comp.lang.lisp] Simple question RE nested DEFUNs

bradb@ai.utoronto.ca (07/31/89)

I come from a Scheme background, where I'm used to defining helping
functions within the body of the function being helped, as in

	(define (foo a)

	  (define (bar b)
	    (... do some stuff with b and return result ...))

	  (... do some stuff with a and call bar as a ...)
	  (... helping function ...))

Now, when I do this in CommonLisp, I notice that the inner DEFUN
(the one for bar in my example) is actually being re-defined on
every invocation of foo.  Eek, this is not what I wanted!  I wanted
the function to be defined exactly once, before foo is ever called,
but available only within the scope of the definition of foo.

I'm sure there is a proper way to do this in CommonLisp, but I'm
not sure what it is.  Could some kind soul please enlighten me?

Thanks very much in advance,
					(-:  Brad Brown  :-)
					bradb@ai.utoronto.ca

(I knew there was a reason I liked Scheme and all it's simplicity...)

lou@bearcat.rutgers.edu (Lou Steinberg) (08/01/89)

In article <89Jul31.114325edt.11243@ephemeral.ai.toronto.edu> bradb@ai.utoronto.ca writes:

> I come from a Scheme background, where I'm used to defining helping
> functions within the body of the function being helped, as in
> 
> 	(define (foo a)
> 
> 	  (define (bar b)
> 	    (... do some stuff with b and return result ...))
> 
> 	  (... do some stuff with a and call bar as a ...)
> 	  (... helping function ...))

> I'm sure there is a proper way to do this in CommonLisp, but I'm
> not sure what it is.  Could some kind soul please enlighten me?

See special forms flet and labels in the manual.

I should point out that these constructs are used much less in lisp
than the corresponding ones in languages like SCHEME or more
traditional nested-scope languages.  I speculate that this is at least
partly because these constructs are harder to support properly in an
interactive programming environment - e.g. to test these helper functions
by calling them interactively you need a way to put yourself (i.e. the
eval of your read-eval-print loop) into the "lexical" context where
the helper function is defined.  This can be implemented, but is a lot
more complex than an environment that only lets you call non-nested
definitions, and so has rarely if ever been implemented in lisp
systems.  (There are a number of other difficulties as well - e.g.
implementing tracing.)

Note also that the same kind of argument could be made about dynamic
vs lexical scoping of variables, but in this case the various costs 
(e.g. in execution and debugging speeds) of dynamic scoping lead most
lisp programmers (or at least those I teach :-) to use primarily
lexical scoping for variables.  Especially with proper use of
packages, the cost of non-nested functions is much less than the cost
of dynamic variables.
-- 
					Lou Steinberg

uucp:   {pretty much any major site}!rutgers!aramis.rutgers.edu!lou 
arpa:   lou@aramis.rutgers.edu

Krulwich@eecs.nwu.edu (Bruce Krulwich) (08/01/89)

In article <89Jul31.114325edt.11243@ephemeral.ai.toronto.edu>, bradb@ai writes:
> I come from a Scheme background, where I'm used to defining helping
> functions within the body of the function being helped, as in
...
> Now, when I do this in CommonLisp, I notice that the inner DEFUN
> (the one for bar in my example) is actually being re-defined on
> every invocation of foo.  Eek, this is not what I wanted!  I wanted
> the function to be defined exactly once, before foo is ever called,
> but available only within the scope of the definition of foo.

The way to do this is to use LABELS, which is completely analogous to LETREC
in Scheme.  

The semantics of internal DEFINE's in Scheme has always seemed screwball to
me, and this seems to be a case where CL is more consistant than Scheme, in
that ALL forms that introduce variables into a binding layer involve nesting
the body over which the variables are scoped.  Additionally, the semantics of
DEFUN are clear: it always defines a global function.


Bruce

gateley@m2.csc.ti.com (John Gateley) (08/01/89)

In article <979@accuvax.nwu.edu> Krulwich@eecs.nwu.edu (Bruce Krulwich) writes:
>...  Additionally, the semantics of
>DEFUN are clear: it always defines a global function.

Not true: defun is a top level form; its semantics are defined only
in the case where it appears at top level (see CLtL chap 5). In the
case mentioned in the original article, the defun does not appear
at top level.

John
gateley@m2.csc.ti.com

bradb@ai.utoronto.ca (08/01/89)

Thanks to everybody who replied to my question.  My mailbox was flooded
with helpful replies within the hour (really!) and my problem is now
solved.

					(:-  Brad Brown  :-)
					bradb@ai.utoronto.ca

jeff@aiai.ed.ac.uk (Jeff Dalton) (08/02/89)

In article <86124@ti-csl.csc.ti.com> gateley@m2.UUCP (John Gateley) writes:
>In article <979@accuvax.nwu.edu> Krulwich@eecs.nwu.edu (Bruce Krulwich) writes:
>>...  Additionally, the semantics of
>>DEFUN are clear: it always defines a global function.
>
>Not true: defun is a top level form; its semantics are defined only
>in the case where it appears at top level (see CLtL chap 5). In the
>case mentioned in the original article, the defun does not appear
>at top level.

Page 66 supports your view.  Page 67, however, says:

   Evaluating a {\tt defun} form causes the symbol {\it name} to be
   a global name for the function specified by the lambda-expression

      (lambda ...)

   defined in the lexical environment in which the {\tt defun} form
   was executed.  Because {\tt defun} forms normally apear at top
   level, this is normally the null lexical environment.

It's possible to argue for a long time about whether page 66 or
page 67 should win.  X3J13 may have decided this one way or the
other by now.  But most implementations do allow {\tt defun} in
non-top-level contexts.

Note too that it's possible to come up with examples in which
a non-top-level {\tt defun} is silly.  But that doesn't show
that every case is silly.  And, indeed, there are times when
non-top-level {\tt defun} makes sense.

Jeff Dalton,                      JANET: J.Dalton@uk.ac.ed             
AI Applications Institute,        ARPA:  J.Dalton%uk.ac.ed@nsfnet-relay.ac.uk
Edinburgh University.             UUCP:  ...!ukc!ed.ac.uk!J.Dalton