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

Function cells



    Date: Sat, 3 Sep 1983  14:38 EDT
    From: ZVONA@MIT-OZ
    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)

No, one should write (funcall #'(:property snaboozle quibbix) . args)
just like one should write (funcall #'snaboozle . args) or
(funcall #'(lambda (x) (+ x x)) . args).  The non-uniformity
here is that (funcall 'snaboozle . args) or
(funcall '(lambda (x) (+ x x)) . args) will work at all.

The only problem with writing ((:property snabozzle quibbix) . args)
is that it is visually confusing.  You can't argue that because
((:property snabozzle quibbix) . args) doesn't work that the
idea of a function spec is inelegant!  At most you can say that
a piece of it that should work doesn't.

    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!  
Bullshit.  DEFUN started out life as sugar for DEFPROP, not PUTPROP.
The difference is that the compiler was then considered free to compile
things defined with DEFPROP.  In more modern times, the compiler is
considered free to compile things "quoted" with FUNCTION rather than
QUOTE.  So...
				    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!  

In the current scheme,

(DEFUN FOO (X) (BAR X)) ==>

(SETF #'FOO #'(LAMBDA (X) (BAR X)))

(DEFUN (:PROPERTY FOO :FUN-PROP) (X) (BAR X))  ==>

(SETF #'(:PROPERTY FOO :FUN-PROP) #'(LAMBDA (X) (BAR X)))

    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.

That is indeed the problem with your scheme, it turns function cells
into a confused mess.  It also ignores every shred of consistancy in
favor of your own internal confusion.  Proof by Solipsism is not
acceptable.

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

    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.)

You're right, it is connected.  You can view (FUNCTION ...) as meaning
"do what you do to the CAR of a combination to get the function to be
performed".  It doesn't buy you much to say that what you do with
the FIRST of a form should be the same as what you do the the SECOND.
It just isn't true after you get your hands on the function, especially
in the case of macros.

The distinction here is very much like the distinction between nouns
and verbs in English.  Frequently a word is both a noun and a verb,
but the distinction is clear from context.  For example, LIST is both
a noun and a verb.  I have seen many users of lisps without function
cells SCREW THEMSELVES TO THE WALL by using something as a temporary
variable that happens to also be a function name.  LIST is the most
common offender.  (This is made worse by lisps which defaultly use
dynamic scoping, but people also have screwed themselves doing
(SETQ LIST (GET-ITEM-LIST 'FOO)) at top level).

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

    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) ...)

ARGH!  This does nobody any favors.  It is every bit as bad as you
imagine distinguishing between functions and values is.

This debate really annoys me, partly because not a single new thing has
been said (with the exception of your SETF/DEFUN scheme, which I detest).
Most of the people involved with Common Lisp have faced this issue and
been thinking about it for 5 years or more.  Most of the arguments against
it are based on an unstated assumption that saying (FUNCALL X ...) is
an unwanted complexity rather than a helpful clarification, or that
the slight simplification of eliminating the function cell is worth
sacraficing the clarity, or that the slight simplification of calling
EVAL on the CAR of the form is worth anything at all.

What I don't understand is why everybody goes on about the FUNCTION cell
in favor of the VALUE cell.  Why isn't anybody proposing we do away with
the VALUE cell.  The history of the VALUE cell in MacLisp *IS THE SAME
AS THAT OF THE FUNCTION CELL*.  I.e. they both used to simply be
properties on the property list.  The evaluator would do a (GET SYMBOL
'VALUE), just like it would do a (GET SYMBOL 'EXPR).  It is obvious that
these are both properties of a symbol, just like (GET SYMBOL 'SI:FLAVOR)
is.

Really, let's not go half-way.  Let's take the argument for merging the
VALUE and FUNCTION properties to its logical extreme, and eliminate the
property-list altogether!

Personally, I'd rather keep distinct meanings separate (noun-meaning
(value), verb-meaning (function), adjective-meaning (flavor)), and try
to have the most EXPRESSIVE language, not the SIMPLEST language.