[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Function cells



The "function spec" problem in Common Lisp is one that makes clear the
advantages of treating "functions and values" uniformly.

It is common to store functions as properties of symbols.  This allows
a clean implementation of data-directed dispatching: you write
(funcall (get snabozzle 'quibbix) . args) in order to do a
quibbix-type dispatch on the snabozzle.  To support this, you want a
clean way to write the functions that will be stored on the property
list and to get them into the property list.  In a lambda calculus
system, you might write

(put 'some-snabozzle 'quibbix (lambda ...))

but modern lisps have defun, which has a lot of useful syntax that
you'd like to use in defining the dispatched-to functions.

Maclisp provided the syntax

(defun (some-snabozzle quibbix) arglist . body)

which would effectively macroexpand into the same thing (and also hack
defun-syntax and process declarations and so forth for you).  This
syntax had a number of problems; among them, especially, that besides
the "function cell" and properties there are other places that you
might want to store functions.  Therefore, lisp machine lisp did an
almost-upward-compatible extension to this in which the defun name
(first subform) if a list would dispatch on the car of the list if
possible.  The car of the list could then be a keyword that would tell
where to put the function.

(defun (:property some-snabozzle quibbix) arglist . body)  

for example.  These lists (such as (:property ...)) were called
"function specs".  The lisp machine provides for each function spec a
set of things that can be done to it: you can define it, undefine it
(make it unbound), get its definition, and so on.  

All this amounts to a fair amount of conceptual overhead (though to
total amount of code to implement it fits in a few pages).  It is no
longer obvious just what it is that defun abstractly macroexpands
into; it is doing some magic with the function specs behind your back.
Moreover, it is often unclear in what contexts it is allowable to use
a function spec.  For example, beginners who are first introduced to
function specs often try to write

((:property snabozzle quibbix) . args)

or

(funcall (:property snabozzle quibbix) . args)

This suggests that perhaps what one ought to be writing is

(defun (get 'some-snabozzle 'quibbix) arglist . body)

because it is intuitively clearer if the defining and using forms have
the same syntax.  Moreover, this eliminates all the overhead of
function specs.  And then defun again has a clear macroexpansion: it
is really just sugar for setf!  That is, the defun above is really

(setf (get 'some-snabozzle 'quibbix) (lambda arglist . body))

There is just one difficulty with this: what does

(defun drofnats (self) (capitalize (string-reverse self)))

macroexpand into?  It ought to be

(setf drofnats (lambda (self) (capitalize (string-reverse self))))

but that sets the value cell, not the function cell!  

This, finally, is the point: The elegant setf syntax for defun was
abandoned for common lisp because it didn't "work" on symbols.  The
true story is that the uniform handling of functions as values is a
self-consistent system, and function cells are a confused mess.

***		***		***		***

It is worth mentioning that (function ...) is intimately tied up with
the function cell lossage.  Common lisp weirdly chose to implement
lambda right, but to require a no-op #' in front of it.  (Anyone who
wants to win, of course, can define lambda as a macro that expands
into #'(lambda ...).  Takes all kinds.)

***		***		***		***

Common lisp people:

defun setf syntax seems like such a win that perhaps it could be
salvaged by the following klduge (which seems better than function
specs): 

defun has setf-syntax except on symbols.  It uses the function cell
with symbols.  You can set the value cell of a symbol with 

(defun (symbol-value symbol) ...)