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