brian@granite.jpl.nasa.gov (Brian of ASTD-CP) (06/29/90)
I spent last weekend reading Steele's CLtL2 (Common Lisp the Language, second edition). What a tour de force! I think I'll be dizzy for at least another week. I have one pressing question about CL. What is the rationale behind the (function ...) or #' construct? It seems in some places you need to say #'foo, say in an apply, and in other places you just say foo, as in (foo 1 2 3). Thus it seems to be the programmer's job to remember when "the function itself" and "the name of the function" are needed by CL. What I mean is, why is this in the language? The book is very thorough on the _rules_for_using_ #', so I don't need your help with that. I can't find any rationale in the book, though. Does it allow the compiler to improve efficiency? Is it there for historical reasons? What gives? I'm most familiar with Scheme/T, where this kind of thing is not necessary. All symbols are evaluated the same way in application expressions (func arg arg), and the value of func is a function. Treating a function as just another data type like integer or string seems very neat and clean. There must be some reason it's not done this way in CL. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Brian Beckman . . . . . . . . . . brian@granite.jpl.nasa.gov. . . . . . meta-disclaimer: every statement in this message is false . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
lgm@cbnewsc.att.com (lawrence.g.mayka) (06/29/90)
In article <4204@jato.Jpl.Nasa.Gov> brian@granite.Jpl.Nasa.Gov (Brian of ASTD-CP) writes: >I have one pressing question about CL. What is the rationale >behind the (function ...) or #' construct? It seems in some >places you need to say #'foo, say in an apply, and in other >places you just say foo, as in (foo 1 2 3). Thus it seems to >be the programmer's job to remember when "the function itself" >and "the name of the function" are needed by CL. This issue is discussed in considerable detail in Volume 1, Number 1, of the journal "Lisp and Symbolic Computation," published by Kluwer Academic Publishers, in a paper authored by Richard Gabriel and Kent Pitman and entitled, "Endpaper: Technical Issues of Separation in Function Cells and Value Cells." Lawrence G. Mayka AT&T Bell Laboratories lgm@iexist.att.com Standard disclaimer.
jearly@lehi3b15.csee.Lehigh.EDU (John Early) (07/04/90)
In article <1990Jun29.162248.7846@Neon.Stanford.EDU> max@Neon.Stanford.EDU (Max Hailperin) writes: In article <4204@jato.Jpl.Nasa.Gov> brian@granite.Jpl.Nasa.Gov (Brian of ASTD-CP) writes: >[...] I have one pressing question about CL. What is the rationale >behind the (function ...) or #' construct? [...] >I'm most familiar with Scheme/T, where this kind of thing is >not necessary. All symbols are evaluated the same way [...] >Treating a function as just another data type >like integer or string seems very neat and clean. There must >be some reason it's not done this way in CL. It's done this way for the sake of people who like to call an argument that's a list "list" and still be able to use the "list" function, as in (defun foo (list) "Return a list of the sum of the list and the sum-of-squares of the list." (list (apply #'+ list) (apply #'+ (mapcar #'square list)))) instead of having to call it the-list like you would in scheme. [Of course, this applies to other names as well, list is just a common one.] Since this is bad programming (at best) I suspect that that is not the reason. I would guess that there is instead an historical/compatibility reason. John. ---------------------------------------- John Early | jearly@lehi3b15.csee.lehigh.edu | I was just a child then; JPE1@Lehigh.Bitnet | now I'm only a man. [pf] LUJPE@VAX1.cc.lehigh.edu |
max@Neon.Stanford.EDU (Max Hailperin) (07/04/90)
In article <1005@lehi3b15.csee.Lehigh.EDU> jearly@lehi3b15.csee.Lehigh.EDU (John Early) writes: >In article <1990Jun29.162248.7846@Neon.Stanford.EDU> max@Neon.Stanford.EDU > (Max Hailperin) writes: > > In article <4204@jato.Jpl.Nasa.Gov> brian@granite.Jpl.Nasa.Gov > (Brian of ASTD-CP) writes: > >[...] I have one pressing question about CL. What is the rationale > >behind the (function ...) or #' construct? [...] > >I'm most familiar with Scheme/T, where this kind of thing is > >not necessary. All symbols are evaluated the same way [...] > >Treating a function as just another data type > >like integer or string seems very neat and clean. There must > >be some reason it's not done this way in CL. > > It's done this way for the sake of people who like to call an argument > that's a list "list" and still be able to use the "list" function, as in > > (defun foo (list) > "Return a list of the sum of the list and the sum-of-squares of the list." > (list (apply #'+ list) > (apply #'+ (mapcar #'square list)))) > > instead of having to call it the-list like you would in scheme. > [Of course, this applies to other names as well, list is just a common one.] >Since this is bad programming (at best) I suspect that that is not the reason. >I would guess that there is instead an historical/compatibility reason. Well, I was trying to cook up a simple example that gives the general flavor of the issue, and that is partially at fault. But yes, there is very definitely a historical compatability issue involved as well: the seperation between procedure and variable name spaces originated back in the days when all variables were dynamically scoped. Thus, you wouldn't just have to call your lists "the-list" instead of "list" if you yourself wanted to use the list proceudre. Rather, you would have to do it all the time unless you could be sure that no function you called--written in general by someone else--happened to use the list function. Further, higher-order procedures were a lot less used and usable in those days, so there wasn't as high a price to pay either. Procedures were almost always intended to be static top-level things, for which dynamic binding was almost always the wrong thing, so it made sense for them to be in a seperate namespace so you couldn't accidentally shadow them. These issues explain why what was appropriate for Lisp 1.5 wasn't appropriate for Scheme. Common Lisp, of course, decided to go with tradition.
dsr@luke.mitre.org (Douglas S. Rand) (07/05/90)
In article <1005@lehi3b15.csee.Lehigh.EDU>, jearly@lehi3b15.csee.Lehigh.EDU (John Early) writes: |>In article <1990Jun29.162248.7846@Neon.Stanford.EDU> max@Neon.Stanford.EDU (Max Hailperin) writes: |> |> In article <4204@jato.Jpl.Nasa.Gov> brian@granite.Jpl.Nasa.Gov |> (Brian of ASTD-CP) writes: |> >[...] I have one pressing question about CL. What is the rationale |> >behind the (function ...) or #' construct? [...] |> >I'm most familiar with Scheme/T, where this kind of thing is |> >not necessary. All symbols are evaluated the same way [...] |> >Treating a function as just another data type |> >like integer or string seems very neat and clean. There must |> >be some reason it's not done this way in CL. |> |> It's done this way for the sake of people who like to call an argument |> that's a list "list" and still be able to use the "list" function, as in |> |> (defun foo (list) |> "Return a list of the sum of the list and the sum-of-squares of the list." |> (list (apply #'+ list) |> (apply #'+ (mapcar #'square list)))) |> |> instead of having to call it the-list like you would in scheme. |> [Of course, this applies to other names as well, list is just a common one.] |>Since this is bad programming (at best) I suspect that that is not the reason. |>I would guess that there is instead an historical/compatibility reason. |>John. |> For those unwilling to read Gabriel and Pitman's paper... First it is naive to simply claim 'bad programming'. The reason CL has both function and value cells to start with is that it is a derivative of the MacLISP/ZetaLISP school of LISP languages. The reason for having two cells is indeed to prevent problems where a name is used for both a function and variable. It is neither 'good' nor 'bad' programming practice. It is very easy to have this happen in real applications. CL is not Scheme. Scheme is a language where symbols have only one 'value'. You therefore need no special syntax to claim to access the function cell of a function over the value cell. But for those who believe collapsing the function and value cells together simplifies things alot, think again. There are not just two namespaces in CL. More like six or seven. Names are used for tags, types (and classes in CLOS), conditions, packages, as well as values and functions. Past this it's worth noting that the programmer can use the plist of the symbol to add indefinitely more interpretations of the symbol. There are many purist reasons for combining function and value namespaces not the least of which is greater simplicity of language. One can get rid of the duality of functions and contructs like flet, fmakeunbound, symbol-function and syntactic contstructs like #'. Douglas S. Rand Internet: <dsrand@mitre.org> Snail: MITRE, Burlington Road, Bedford, MA Disclaimer: MITRE might agree with me - then again...
masinter@parc.xerox.com (Larry Masinter) (07/07/90)
Macros can have unintended interactions with lexical functions in a way that is as bad as the interaction of dynamic variables. For example, in: (defmacro double (x) (let ((y x)) (list y y))) (defun oops (list) (double list)) is the "list" referenced under double the same or different than the argument to oops? I think the effort to merge function and value cells in Common Lisp foundered, not so much because of a preference for tradition but rather that no workable replacement for Common Lisp macros could be found that retained the power without adding unacceptable complexity. It is difficult to take something as complex as Common Lisp, tweak one part and actually make it better rather than worse. Standard Scheme doesn't have macros; I believe several Scheme implementations have macros, but I don't remember the details. -- 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
masinter@parc.xerox.com (Larry Masinter) (07/08/90)
In article <MASINTER.90Jul6230837@brainiac.parc.xerox.com> I write: > (defmacro double (x) > (let ((y x)) > (list y y))) > (defun oops (list) > (double list)) and I meant (defmacro double (x) `(let ((y ,x)) (list y y))) (defun oops (list) (double list)) The fact that macros capture lexical functions and that much of Common Lisp potentially involves macro expansion means that any rebinding of predefined symbols is potentially ambiguous, e.g., (flet ((cons (x y) (cons y x))) `(,1 . ,2)) or (FLET ((OPEN (filename &key direction) (format t "Open called....") (OPEN filename :direction direction))) (with-open-file (x "frob" :direction ':output) (format t "was Open called?"))) -- 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
cowan@marob.masa.com (John Cowan) (07/12/90)
In article <1005@lehi3b15.csee.Lehigh.EDU>, jearly@lehi3b15.csee.Lehigh.EDU (John Early) writes: And in article <1990Jun29.162248.7846@Neon.Stanford.EDU>, max@Neon.Stanford.EDU (Max Hailperin) writes: And in article <4204@jato.Jpl.Nasa.Gov> brian@granite.Jpl.Nasa.Gov (Brian of ASTD-CP) writes: Brian> [...] I have one pressing question about CL. What is the rationale Brian> behind the (function ...) or #' construct? [...] Brian> I'm most familiar with Scheme/T, where this kind of thing is Brian> not necessary. All symbols are evaluated the same way [...] Max> It's done this way for the sake of people who like to call an argument Max> that's a list "list" and still be able to use the "list" function, as in Max> (defun foo (list) Max> "Return a list of the sum of the list and the sum-of-squares of the list." Max> (list (apply #'+ list) Max> (apply #'+ (mapcar #'square list)))) Max> Max> instead of having to call it the-list like you would in scheme. Max> [Of course, this applies to other names as well, list is just a common one.] JEarly> Since this is bad programming (at best) I suspect that that is not the reason. JEarly> I would guess that there is instead an historical/compatibility reason. Max and JEarly are both right: the use of (function ...) does indeed stem from the desire to be backward compatible with older LISPS, specifically in the ability to give a symbol both a function and a non-function ("value") binding. In the oldest Lisps, the value was stored in a global association list to which new entries were added as needed (all variables were special), whereas the function binding was stored on the symbol's property list. Later, the value binding was moved to the property list as well, and saved/restored as needed; still later (MACLisp), the value was placed in a slot of the symbol object itself; still later (most Common Lisps), both the value and the function binding were moved to slots. Scheme, having the advantage of dismissing backward compatibility (eq vs. eq?, for example), could go for the one-symbol-one-binding style and did so. A subtler point: in pre-Common Lisps, where there were officially no lexical variables (except in compiled code, where the compiler "sneaked them in" unless prevented by a special declaration), (function ...) had the effect of capturing the current >dynamic< bindings, a property it no longer has in Common Lisp. Typically, (function ...) was a special form which returned a triplet (FUNARG function environment) where environment could be either an a-list or a stack pointer. When applied, "FUNARG triples" would have the effect of temporarily restoring the dynamic environment in the third component for the duration of the application. Whether changes to that dynamic environment were preserved after the FUNARG terminated was implementation-dependent, as was whether it was safe to use "upward FUNARGS" that referred to dynamic environments that had already exited. In the new world of mostly lexical variables all of this cruft goes away. -- cowan@marob.masa.com (aka ...!hombre!marob!cowan) e'osai ko sarji la lojban