[comp.lang.lisp] Dumb Common Lisp question

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