engber@speedy.cs.wisc.edu (Mike Engber) (06/21/88)
What does nesting function definition do in Common Lisp? For example: (defun cube (x) (defun square (x) (* x x)) (* x (square x))) I saw this style of coding in an article. I played around with it using Allegro Common Lisp (on a Mac) and it seems to create some sort of closure. It also seems to me that this is a more inefficient way to do "PASCAL" style nesting than using FLET. Does anyone what this nesting really does? -ME
sandra@utah-cs.UUCP (Sandra J Loosemore) (06/21/88)
In article <5862@spool.cs.wisc.edu>, engber@speedy.cs.wisc.edu (Mike Engber) writes: > What does nesting function definition do in Common Lisp? For example: > > (defun cube (x) > (defun square (x) > (* x x)) > (* x (square x))) > > I saw this style of coding in an article. I played around with it using > Allegro Common Lisp (on a Mac) and it seems to create some sort of closure. > It also seems to me that this is a more inefficient way to do "PASCAL" > style nesting than using FLET. Does anyone what this nesting really does? Strictly speaking, Common Lisp does not (yet) support DEFUN except at "top-level" locations; see CLtL p. 66. However, there is currently a proposal before X3J13 (the ANSI Common Lisp standardization committee) to clarify and extend the language on this point. Under this proposal, DEFUN would always set the *global* function definition of the symbol (unlike FLET, which establishes a lexical function binding). In your example above, the symbol-function of SQUARE would be setf'ed each time CUBE is entered. Since no variables that are closed over are referenced inside the body of SQUARE, the function would not necessarily have to be represented as a closure. Note that the functional binding of SQUARE persists after CUBE has been exited. -Sandra Loosemore (sandra@cs.utah.edu)
barmar@think.COM (Barry Margolin) (06/22/88)
In article <5862@spool.cs.wisc.edu> engber@speedy.cs.wisc.edu (Mike Engber) writes: >What does nesting function definition do in Common Lisp? For example: > >(defun cube (x) > (defun square (x) > (* x x)) > (* x (square x))) Sandra gave an answer about the above definition, and described a proposal that is currently being considered by the standardization committee. The above example, however, doesn't show off the more interesting aspects of the proposed extension to the language, because it shadows parameter variables, so no variables get closed over. Consider instead: (defun weirdo (x) (defun weirdo-internal (y) (+ x y)) (weirdo-internal (sqrt x))) What does (weirdo 4) do? It actually has what I think of as a first-order behavior and a second-order behavior. The first-order behavior is that it returns 6 (it computes (+ 4 (sqrt 4))). However, as Sandra pointed out, it also sets the global function binding of the WEIRDO-INTERNAL symbol; this is the second-order behavior. If you were to then do (weirdo-internal 10), the returned value would be 14, because WEIRDO-INTERNAL's function binding is a closure over the value of X as of the last time WEIRDO was called. If you then do (weirdo 9), it will return 12, and the next (weirdo-internal 10) will return 19. Barry Margolin Thinking Machines Corp. barmar@think.com {uunet,harvard}!think!barmar
barmar@think.COM (Barry Margolin) (06/22/88)
In article <3257@ubc-cs.UUCP> manis@faculty.cs.ubc.ca (Vincent Manis) writes: >I think it's a mistake to define an internal definition to change the >*global* value of the function cell: this is almost always not what >one would expect, given lexical binding. Either don't provide it at >all (as CL doesn't) or give it the same semantics as in Scheme. Why is it any wronger for DEFUN to change the global value than it is for SETQ? The way I think of it, DEFUN is to FLET/LABELS as SETQ is to LET. This does bring up a good question for the X3J13 compiler subcommittee to consider. What does: (defun foo (x) (flet ((internal (y) (+ x y))) (defun internal (y) (* x y)) (internal 3))) do? If my analogy is completely correct, this shouldn't have any effect on INTERNAL's global function cell. From what I remember at the X3J13 meeting, I think my analogy is incorrect. I think the analogy that the compiler subcommittee is using is DEFUN is to FLET as (SETF SYMBOL-VALUE) is to FLET, i.e. (DEFUN name ...) macroexpands into (SETF (SYMBOL-FUNCTION 'name) #'(LAMBDA ...)) plus some unspecified implementation-specific stuff. Barry Margolin Thinking Machines Corp. barmar@think.com {uunet,harvard}!think!barmar
sandra@utah-cs.UUCP (Sandra J Loosemore) (06/22/88)
In article <22427@think.UUCP>, barmar@think.COM (Barry Margolin) writes: > I think the analogy that the compiler subcommittee is > using is DEFUN is to FLET as (SETF SYMBOL-VALUE) is to FLET, i.e. > (DEFUN name ...) macroexpands into (SETF (SYMBOL-FUNCTION 'name) > #'(LAMBDA ...)) plus some unspecified implementation-specific stuff. Yes, that is essentially correct, except I think you really meant to say LET instead of FLET at the end of the second line. If you wanted a DEFUN inside an FLET or LABELS to be able to redefine a local function, you'd either have to make it a special form or define a new special form for it to expand into. The problem is that Common Lisp doesn't provide anything analagous to SETQ that can magically modify either a lexical function binding or a global function binding, depending on the context in which it appears. Personally, I think Common Lisp has quite enough special forms already, and I'm not convinced that such a "feature" would be particularly useful anyway. -Sandra
caldwell@akhenaten.steinmetz (James Caldwell) (06/22/88)
In article <5568@utah-cs.UUCP> sandra@utah-cs.UUCP (Sandra J Loosemore) writes: >In article <5862@spool.cs.wisc.edu>, engber@speedy.cs.wisc.edu (Mike Engber) writes: >> What does nesting function definition do in Common Lisp? For example: ... > >Strictly speaking, Common Lisp does not (yet) support DEFUN except at >"top-level" locations; see CLtL p. 66. ... > Steele leaves it open, see CLtL p. 67, where he describes what the proper lexical environment should be for a defun form that does not appear at the top-level. In their interpreters, Lucid and Franz both correctly handle the case (let ((x 1)) (defun y () x)) returning 1 when y is called. Unfortunately they complain if you try to compile y since y's lexical environment is not empty. Nesting defuns within the scope of a let is very useful for defining variables and functions that are global to a couple of named functions. This technique is used a number of times in Charniak, Riesbeck, McDermott and Meehan's book _Artifical_Intelligence_Programming_. Of course the same effect can be had by collecting those couple of functions into their own package, defvaring the variables and defuning the functions and then exporting only the desired named functions. A lexical closure is a simpler and more elegant mechanism and avoids a proliferation of packages. >... there is currently a proposal before X3J13 ... Under this >proposal, DEFUN would always set the *global* function definition of >the symbol ... I assume the proposal is intended to allow named functions to be defined with a non-empty lexical environment. Sounds good to me. >-Sandra Loosemore (sandra@cs.utah.edu) Jim Caldwell caldwell%akhenaten@steinmetz.UUCP uunet!steinmetz!akhenaten!caldwell Jim Caldwell caldwell%akhenaten@steinmetz.UUCP uunet!steinmetz!akhenaten!caldwell
manis@faculty.cs.ubc.ca (Vincent Manis) (06/23/88)
Barry Margolin asks why I think DEFUN should be local if SETQ can be global. Basically, DEFUN performs an act of *binding*, whereas SETQ does an *assignment*. A function or value cell need not exist prior to DEFUN (or any other DEF form), whereas such a cell must exist prior to SETQ. Because of this difference, I see DEFUN as a lot closer to LET than it is to SETQ. Since LET is lexically scoped, so too should DEFUN. Vincent Manis | manis@cs.ubc.ca The Invisible City of Kitezh | manis@cs.ubc.cdn Department of Computer Science | manis@ubc.csnet University of British Columbia | uunet!ubc-cs!manis <<NOTE NEW ADDRESS>> |
barmar@think.COM (Barry Margolin) (06/29/88)
In article <3266@ubc-cs.UUCP> manis@faculty.cs.ubc.ca (Vincent Manis) writes: >Barry Margolin asks why I think DEFUN should be local if SETQ can be >global. Basically, DEFUN performs an act of *binding*, whereas SETQ >does an *assignment*. A function or value cell need not exist prior >to DEFUN (or any other DEF form), whereas such a cell must exist prior >to SETQ. Since when? I can do (SETQ *FOO* 3) anyplace where (DEFUN FOO ...) is permitted. While it may be bad style to do this without first doing (DEFVAR *FOO*), I don't think it is invalid. >Because of this difference, I see DEFUN as a lot closer to LET than it >is to SETQ. Since LET is lexically scoped, so too should DEFUN. There is absolutely no precedent for this. All the special forms that instantiate a lexically-scoped name do so only within the body of that special form. You are proposing that in (let (...) (defun foo ...) ...) the scope of FOO would be the entire LET body, i.e. that the DEFUN would affect the environment of the special form that contains it. What about (defun foo () (print 'outer)) (let ((bar nil)) (setq bar #'(lambda () (foo))) (funcall bar) (defun foo () (print 'inner)) (funcall bar)) Does this print OUTER followed by INNER, INNER twice, or does it get an error? I can think of justifications for all of these behaviors. FLET and LABELS already exist for defining functions that can only be accessed within a lexical scope. What additional function does your lexical DEFUN provide? Barry Margolin Thinking Machines Corp. barmar@think.com {uunet,harvard}!think!barmar
jeff@aiva.ed.ac.uk (Jeff Dalton) (07/06/88)
In article <5568@utah-cs.UUCP> sandra@utah-cs.UUCP (Sandra J Loosemore) writes: >Strictly speaking, Common Lisp does not (yet) support DEFUN except at >"top-level" locations; see CLtL p. 66. I disagree with this interpretation of CLtL. Page 67 is clearly and explicitly defined the meaning of DEFUN when not at the top-level. Page 66 is relatively vague, but the only thing it definately says may not work is the compilation of such DEFUNs. That is why, after all, this issue has been sent to x3j13's compilewr committee. Jeff Dalton, JANET: J.Dalton@uk.ac.ed AI Applications Institute, ARPA: J.Dalton%uk.ac.ed@nss.cs.ucl.ac.uk Edinburgh University. UUCP: ...!ukc!ed.ac.uk!J.Dalton