Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Hacking CL into a Lisp-1 (an intro to code-walking)

136 views
Skip to first unread message

Hoan Ton-That

unread,
Apr 20, 2006, 3:51:49 AM4/20/06
to
;; Hello fellow Lispers,

;; This article will show you how to turn Common Lisp into a Lisp-1.
;; It uses a technique called code walking. Instead of operating on
;; lists like macros do, we operate on a proper parse tree
;; (represented by CLOS objects, in this case).

;; The arnesi package by Marco Baringer has a code-walker and
;; unwalker, so most of our work is done for us. So lets step into
;; arnesi:
(in-package :arnesi)

;; We define generic function `lisp1' which converts a Lisp-1 form to
;; a Lisp-2 one. We'll be defining methods on it with
;; `deflisp1-walker'.
(defgeneric lisp1 (form))

;; This macro runs the form as if were run in a Lisp-1. Notice how
;; `walk-form' and `unwalk-form' convert the form to and from CLOS
;; objects and lists.
(defmacro with-lisp1 (form)
(unwalk-form (lisp1 (walk-form form))))

;; We'll use `defun1' to define Lisp-1 style functions. Everything
;; inside the body is converted from Lisp-1 to Lisp-2.
(defmacro defun1 (name (&rest args) &body body)
`(defun ,name ,args
(with-lisp1 (progn ,@body))))

;; This defines a Lisp-1 to Lisp-2 converter. It takes the class of a
;; CL form object, and its slots as arguments. It also captures the
;; variable `FORM' for convenience.
(defmacro deflisp1-walker (class (&rest slots) &body body)
`(defmethod lisp1 ((form ,class))
(with-slots ,slots form
,@body)))

;; This is exactly the same as `make-instance' except for the shorter
;; name.
(defun new (class &rest initargs)
(apply #'make-instance class initargs))

;; Likewise.
(defun class-name-of (obj)
(class-name (class-of obj)))

;; Convert a list of forms to Lisp-2. Very convenient.
(defun lisp1s (forms)
(mapcar #'lisp1 forms))

;; We keep a list of variables that are bound by lambdas. Its very
;; inconvenient to pass this around.
(defvar *bound-vars* nil)

;; Okay, by default all forms will stay the same.
(deflisp1-walker form ()
form)

;; ARNESI> (ppm1 (with-lisp1 2))
;; 2
;; ARNESI> (ppm1 (with-lisp1 'hello))
;; 'HELLO

;; So far, all the same. Now for if expressions we transform the
;; branches.
(deflisp1-walker if-form (consequent then else)
(new 'if-form
:consequent (lisp1 consequent)
:then (lisp1 then)
:else (lisp1 else)))

;; ARNESI> (ppm1 (with-lisp1 (if 'hello 'fellow 'lispers)))
;; (IF 'HELLO 'FELLOW 'LISPERS)

;; For any function-form (ie lambda), we just transform the body. We
;; also must add the parameters to the list of bound variables.
(deflisp1-walker lambda-function-form (arguments body)
(let ((*bound-vars* (append (mapcar #'name arguments) *bound-vars*)))
(new 'lambda-function-form
:arguments arguments
:body (lisp1s body))))

;; ARNESI> (ppm1 (with-lisp1 (lambda (x y z) x)))
;; #'(LAMBDA (X Y Z) X)

;; If a free variable is bound in the toplevel, *and* not bound by an
;; enclosing lambda, then we'll return that function. We take
;; advantage of the fact that the `name' slot is shared.
(deflisp1-walker free-variable-reference (name)
(if (and (fboundp name) (not (member name *bound-vars*)))
(change-class form 'free-function-object-form)
form))

;; ARNESI> (ppm1 (with-lisp1 car)) ;(fboundp name) is true
;; #'CAR
;; ARNESI> (ppm1 (with-lisp1 x)) ;(fboundp name) is false
;; X
;; ARNESI> (ppm1 (with-lisp1 (lambda (x) x)))
;; #'(LAMBDA (X) X)
;; ARNESI> (ppm1 (with-lisp1 (lambda (car) car))) ;car is a bound
variable
;; #'(LAMBDA (CAR) CAR)
;; ARNESI> (ppm1 (with-lisp1 (lambda (x) car)))
;; #'(LAMBDA (X) #'CAR) ;car is not bound by a lambda, but bound at the
toplevel

;; We transform all applications so they use explicit funcall.
;; We also must take into account ((a b) c ...) which must also
;; transform the operator accordingly.
(deflisp1-walker application-form (operator arguments)
(new 'free-application-form
:operator 'funcall
:arguments (cons (if (not (typep operator 'form))
(lisp1 (walk-form operator))
(lisp1 operator))
(lisp1s arguments))))

;; ARNESI> (ppm1 (with-lisp1 (car '(1 2))))
;; (FUNCALL #'CAR '(1 2))
;; ARNESI> (ppm1 (with-lisp1 (mapcar car '((1 2) (3 4)))))
;; (FUNCALL #'MAPCAR #'CAR '((1 2) (3 4)))
;; ARNESI> (ppm1 (with-lisp1 ((curry + 2) 3)))
;; (FUNCALL (FUNCALL #'CURRY #'+ 2) 3)
;; ARNESI> (ppm1 (with-lisp1 ((lambda (x y) (cons y x)))))
;; (FUNCALL #'(LAMBDA (X Y) (FUNCALL #'CONS Y X)))

;; Here are the rest of the Common Lisp forms:

;; Convert an alist of bindings to Lisp-2. Used when walking `let',
;; `let*', `flet' and the like.
(defun lisp1b (binds)
(mapcar #'(lambda (bind)
(cons (car bind)
(lisp1 (cdr bind))))
binds))

(deflisp1-walker function-binding-form (binds body)
(new (class-name-of form)
:binds (lisp1b binds)
:body (lisp1s body)))

(deflisp1-walker variable-binding-form (binds body)
(new (class-name-of form)
:binds (lisp1b binds)
:body (lisp1s body)))

(deflisp1-walker setq-form (var value)
(new 'setq-form
:var var
:value (lisp1 value)))

(deflisp1-walker progn-form (body)
(new 'progn-form
:body (lisp1s body)))

(deflisp1-walker progv-form (vars-form values-form)
(new 'progv-form
:vars-form (lisp1s vars-form)
:values-form (lisp1s values-form)))

(deflisp1-walker block-form (name body)
(new 'block-form
:name name
:body (lisp1s body)))

(deflisp1-walker catch-form (tag body)
(new 'catch-form
:tag tag
:body (lisp1s body)))

(deflisp1-walker multiple-value-call-form (func arguments)
(new 'multiple-value-call-form
:func (lisp1 func)
:arguments (lisp1s arguments)))

(deflisp1-walker multiple-value-prog1-form (first-form other-forms)
(new 'multiple-value-prog1-form
:first-form (lisp1 first-form)
:other-forms (lisp1s other-forms)))

(deflisp1-walker symbol-macrolet-form (binds body)
(new 'symbol-macrolet-form
:binds (lisp1b binds)
:body (lisp1s body)))

(deflisp1-walker tagbody-form (body)
(new 'tagbody-form
:body (lisp1s body)))

(deflisp1-walker the-form (type-form value)
(new 'the-form
:type-form type-form
:value (lisp1 value)))

(deflisp1-walker unwind-protect-form (protected-form cleanup-form)
(new 'unwind-protect-form
:protected-form (lisp1 protected-form)
:cleanup-form (lisp1 cleanup-form)))

;; We can also define the Y combinator in Lisp-1 style, just for fun:
(defun1 Y (f)
((lambda (x)
(f (lambda (y) ((x x) y))))
(lambda (x)
(f (lambda (y) ((x x) y))))))

;; As opposed the the very verbose Lisp-2 style:
(defun Y (f)
(funcall #'(lambda (x)
(funcall f #'(lambda (y) (funcall (funcall x x) y))))
#'(lambda (x)
(funcall f #'(lambda (y) (funcall (funcall x x) y))))))

;; Now you have the choice between Lisp-1 and Lisp-2 styles.
;; And that folks, is how you do code walking!

;; Hoan

;; For more of a discussion of Lisp-1 vs Lisp-2 see
;; http://www.dreamsongs.com/Separation.html.

mac

unread,
Apr 20, 2006, 4:56:30 AM4/20/06
to
Very cool hack. Ron Garret should be happy that he can use lisp1
functional style in CL.

The code walker and cps transformation in arnesi is very interesting. I
still haven't tackled Lisp in small pieces yet so I cannot fully
understand the code (I think the book explains some of the concepts
behind). But this is in my todo list :-)

Thanks for the interesting article.
-- Mac

David Sletten

unread,
Apr 20, 2006, 5:25:55 AM4/20/06
to
Hoan Ton-That wrote:


> ;; We can also define the Y combinator in Lisp-1 style, just for fun:
> (defun1 Y (f)
> ((lambda (x)
> (f (lambda (y) ((x x) y))))
> (lambda (x)
> (f (lambda (y) ((x x) y))))))
>
> ;; As opposed the the very verbose Lisp-2 style:
> (defun Y (f)
> (funcall #'(lambda (x)
> (funcall f #'(lambda (y) (funcall (funcall x x) y))))
> #'(lambda (x)
> (funcall f #'(lambda (y) (funcall (funcall x x) y))))))
>

This is a trivial issue, but you don't need the first FUNCALL:
(defun Y (f)
((lambda (x)


(funcall f #'(lambda (y) (funcall (funcall x x) y))))
#'(lambda (x)
(funcall f #'(lambda (y) (funcall (funcall x x) y))))))

Aloha,
David Sletten

Hoan Ton-That

unread,
Apr 20, 2006, 6:55:26 AM4/20/06
to
Yes, yes...

One of the wierd things about CL is that you can't have:

(#'(lambda (x) x) 'x)

The caar of the form must be 'lambda. So its not immediately
obvious that you can drop funcall, especially when lots of
people unneccesarily sharp-quote their lambdas...

David Sletten

unread,
Apr 20, 2006, 2:25:25 PM4/20/06
to
Hoan Ton-That wrote:

Well let's be clear, there is no unnecessary quoting of lambdas. The
sharp-quote notation is syntactic sugar for the FUNCTION special
operator, which is required to create a closure from a lambda
expression. It just so happens that Common Lisp also has a LAMBDA macro
which provides a syntactic shortcut for this same operation, but this
doesn't change the fundamental underlying use of FUNCTION (or sharp-quote).

LAMBDA is serving 2 different roles here:
((lambda (x) (* x 9)) 3) ;Lambda expression applied to arg 3
(mapcar (lambda (l) (first l)) '((a b) (c d) (e f))) ;LAMBDA macro
equivalent to...
(mapcar #'(lambda (l) (first l)) '((a b) (c d) (e f))) ;FUNCTION (#')
applied to lambda expression

Aloha,
David Sletten

Thomas F. Burdick

unread,
Apr 21, 2006, 8:43:23 AM4/21/06
to
David Sletten <da...@slytobias.com> writes:

> Hoan Ton-That wrote:
>
> > Yes, yes...
> > One of the wierd things about CL is that you can't have:
> > (#'(lambda (x) x) 'x)
> > The caar of the form must be 'lambda. So its not immediately
> > obvious that you can drop funcall, especially when lots of
> > people unneccesarily sharp-quote their lambdas...
> >
> Well let's be clear, there is no unnecessary quoting of lambdas. The
> sharp-quote notation is syntactic sugar for the FUNCTION special
> operator, which is required to create a closure from a lambda
> expression. It just so happens that Common Lisp also has a LAMBDA
> macro which provides a syntactic shortcut for this same operation, but
> this doesn't change the fundamental underlying use of FUNCTION (or
> sharp-quote).

Thus making the sharp-quote unnecessary. The LAMBDA macro expands
into something that evaluates to a function -- no need to write out
its macroexpansion any more than there is for PUSH.

--
/|_ .-----------------------.
,' .\ / | Free Mumia Abu-Jamal! |
,--' _,' | Abolish the racist |
/ / | death penalty! |
( -. | `-----------------------'
| ) |
(`-. '--.)
`. )----'

David Sletten

unread,
Apr 21, 2006, 2:20:56 PM4/21/06
to
Thomas F. Burdick wrote:

> David Sletten <da...@slytobias.com> writes:
>
>
>>Hoan Ton-That wrote:
>>
>>
>>>Yes, yes...
>>>One of the wierd things about CL is that you can't have:
>>>(#'(lambda (x) x) 'x)
>>>The caar of the form must be 'lambda. So its not immediately
>>>obvious that you can drop funcall, especially when lots of
>>>people unneccesarily sharp-quote their lambdas...
>>>
>>
>>Well let's be clear, there is no unnecessary quoting of lambdas. The
>>sharp-quote notation is syntactic sugar for the FUNCTION special
>>operator, which is required to create a closure from a lambda
>>expression. It just so happens that Common Lisp also has a LAMBDA
>>macro which provides a syntactic shortcut for this same operation, but
>>this doesn't change the fundamental underlying use of FUNCTION (or
>>sharp-quote).
>
>
> Thus making the sharp-quote unnecessary. The LAMBDA macro expands
> into something that evaluates to a function -- no need to write out
> its macroexpansion any more than there is for PUSH.
>

As I made clear in my post, there is _fundamentally_ no unnecessary
sharp-quoting--either you do it or Lisp does it. I was trying to clarify
for the OP the potentially confusing dual use of LAMBDA. Considering
that my post already contained all of the information content of your
response, what is it that you think you are accomplishing with your
stylistic quibble?

David Sletten

Ron Garret

unread,
Apr 21, 2006, 2:59:34 PM4/21/06
to
In article <1145523390.1...@u72g2000cwu.googlegroups.com>,
"mac" <emai...@gmail.com> wrote:

> Very cool hack. Ron Garret should be happy that he can use lisp1
> functional style in CL.

Old news. See http://www.flownet.com/gat/locales.pdf section 5.

This does not address the pedagogy problem. If you are teaching CL you
still have to teach it as a Lisp-2 plus a hack for ((lambda ...) ...)

rg

Peter Seibel

unread,
Apr 21, 2006, 3:27:27 PM4/21/06
to
Ron Garret <rNOS...@flownet.com> writes:

Hmmm, I don't see it that way, and I speak from some experience here.
It seems to me that CL is usefully taught as a Lisp-2 where the 2nd
evaluation rule (i.e. the one used to evaluate the CAR's of list forms
and by the special operator FUNCTION) knows about two kinds of
function names, symbols and "eponymous" functions, i.e. lambda's. The
only glitch the pedagog must handwave around is the fact that after
you say:

(defun (setf foo) (x ...) ....)

then:

(function (setf foo)) => #<Interpreted Function (SETF FOO)>

but:

((setf foo) 20 ...)

is an error. But basically you can say (in only slight contradiction
of the Hyperspec) that a function "name" is a symbol, a LAMBDA
expression or a two-item list of the form (SETF <symbol>) and that the
FUNCTION special operator understands all three kinds of names and
either of the first two, but not the third, can be used in the CAR
position of a list form.

-Peter

--
Peter Seibel * pe...@gigamonkeys.com
Gigamonkeys Consulting * http://www.gigamonkeys.com/
Practical Common Lisp * http://www.gigamonkeys.com/book/

Ron Garret

unread,
Apr 22, 2006, 6:51:51 PM4/22/06
to
In article <m2zmieb...@gigamonkeys.com>,
Peter Seibel <pe...@gigamonkeys.com> wrote:

Of course you can say that, but it's not a "slight contradiction to the
spec", it's an outright lie:

? (defun (setf foo) () t)
(SETF FOO)
? ((setf foo))
Error: Car of ((SETF FOO)) is not a function name or lambda-expression.


> and that the
> FUNCTION special operator understands all three kinds of names and
> either of the first two, but not the third, can be used in the CAR
> position of a list form.

I don't see how this is substantially different from what I said.
Whether you choose to present it as a hack for lambda or an anti-hack
for setf, it's still a hack. (Frankly, I think your approach is much
worse because it's a hack AND a lie. My way it's just a hack.)

rg

Peter Seibel

unread,
Apr 22, 2006, 8:00:00 PM4/22/06
to
Ron Garret <rNOS...@flownet.com> writes:

> In article <m2zmieb...@gigamonkeys.com>,
> Peter Seibel <pe...@gigamonkeys.com> wrote:

>> is an error. But basically you can say (in only slight contradiction
>> of the Hyperspec) that a function "name" is a symbol, a LAMBDA
>> expression or a two-item list of the form (SETF <symbol>)
>
> Of course you can say that, but it's not a "slight contradiction to the
> spec", it's an outright lie:
>
> ? (defun (setf foo) () t)
> (SETF FOO)
> ? ((setf foo))
> Error: Car of ((SETF FOO)) is not a function name or lambda-expression.

Actually your implementation is lying to you. According to the
hyperspec a list of the form (SETF <symbol>) *is* a function name.
(Check the glossary entry for "function name".) The slight
contradiction to the spec that I was ignoring is that *lambda
expressions* are not, technically speaking, "function names".

Without contradicting the spec we can say the FUNCTION special
operator takes as it's argument a function name or a lambda expression
while the CAR of a list form representing a function call must be
either a symbol function name or a lambda expression.

>> and that the FUNCTION special operator understands all three kinds
>> of names and either of the first two, but not the third, can be
>> used in the CAR position of a list form.
>
> I don't see how this is substantially different from what I said.
> Whether you choose to present it as a hack for lambda or an anti-hack
> for setf, it's still a hack. (Frankly, I think your approach is much
> worse because it's a hack AND a lie. My way it's just a hack.)

Well the difference is that I'd say the treatment of lambda
expressions as function eponyms, if not technically nyms, is perfectly
consistent, i.e. anywhere you can use a function name to refer to a
function you can also use a lambda expression. (Actually that sort of
makes the distinction between an eponym and a proper name clear--the
one place you *can't* use a lambda expression is, of course, when
giving a function it's name, i.e. in a DEFUN, FLET, or LABELS, since
an eponym by it's nature is *already* the name of the thing it names.)
The only inconsistency (hack, if you will) is that (SETF <symbol>)
names can be used with DEFUN (and, according to the HyperSpec with
FLET and LABELS though that doesn't seem to work in Allegro) and as
arguments to FUNCTION but not in the CAR position of a function call

Ron Garret

unread,
Apr 22, 2006, 8:32:44 PM4/22/06
to
In article <m2zmid9...@gigamonkeys.com>,
Peter Seibel <pe...@gigamonkeys.com> wrote:

> Ron Garret <rNOS...@flownet.com> writes:
>
> > In article <m2zmieb...@gigamonkeys.com>,
> > Peter Seibel <pe...@gigamonkeys.com> wrote:
>
> >> is an error. But basically you can say (in only slight contradiction
> >> of the Hyperspec) that a function "name" is a symbol, a LAMBDA
> >> expression or a two-item list of the form (SETF <symbol>)
> >
> > Of course you can say that, but it's not a "slight contradiction to the
> > spec", it's an outright lie:
> >
> > ? (defun (setf foo) () t)
> > (SETF FOO)
> > ? ((setf foo))
> > Error: Car of ((SETF FOO)) is not a function name or lambda-expression.
>
> Actually your implementation is lying to you.

Whaddya know. My bad. Sorry. I was confusing the definitions of
function names and function designators (I think -- it's all so horribly
confusing sometimes).

> Without contradicting the spec we can say the FUNCTION special
> operator takes as it's argument a function name or a lambda expression
> while the CAR of a list form representing a function call must be
> either a symbol function name or a lambda expression.

True. Still, one could forgive a newcomer for wondering what the payoff
is in all this complexity.

> >> and that the FUNCTION special operator understands all three kinds
> >> of names and either of the first two, but not the third, can be
> >> used in the CAR position of a list form.
> >
> > I don't see how this is substantially different from what I said.
> > Whether you choose to present it as a hack for lambda or an anti-hack
> > for setf, it's still a hack. (Frankly, I think your approach is much
> > worse because it's a hack AND a lie. My way it's just a hack.)
>
> Well the difference is that I'd say the treatment of lambda
> expressions as function eponyms,

Dictionary.com says that "eponym" means:


1 A person whose name is or is thought to be the source of the name
of something, such as a city, country, or era. For example, Romulus is
the eponym of Rome.
2 Medicine. A name of a drug, structure, or disease based on or
derived from the name of a person.

Accordingly, the above makes no sense to me.

> if not technically nyms,

Nyms is not an english word as far as I can determine. (Remember, we're
talking about pedagogy here, so this is not a trivial detail.)

> is perfectly
> consistent, i.e. anywhere you can use a function name to refer to a
> function you can also use a lambda expression.

Not so:

? (defun foo () t)
FOO
? (setf function-name-1 'foo)
FOO
? (setf function-name-2 '(lambda () t))
(LAMBDA NIL T)
? (funcall function-name-1)
T
? (funcall function-name-2)
> Error: (LAMBDA NIL T) can't be FUNCALLed or APPLYed.


rg

Peter Seibel

unread,
Apr 22, 2006, 9:16:10 PM4/22/06
to
Ron Garret <rNOS...@flownet.com> writes:

> Dictionary.com says that "eponym" means:
>
> 1 A person whose name is or is thought to be the source of the name
> of something, such as a city, country, or era. For example, Romulus is
> the eponym of Rome.
> 2 Medicine. A name of a drug, structure, or disease based on or
> derived from the name of a person.
>
> Accordingly, the above makes no sense to me.

Well, it may be stretching the metaphor a bit but a lambda expression
both is the function (i.e. it is Romulus) and it gives the function
(what passes for) it's name.

>> if not technically nyms,
>
> Nyms is not an english word as far as I can determine. (Remember,
> we're talking about pedagogy here, so this is not a trivial detail.)

I'm sorry if you didn't get the joke and doubly sorry if it actually
confused you. Humour is always a tricky thing, but it can be a useful
pedagogical tool. (Helps keep the student from falling asleep,
drooling on your book, and getting the pages stuck to their face.)

>> is perfectly consistent, i.e. anywhere you can use a function name
>> to refer to a function you can also use a lambda expression.
>
> Not so:
>
> ? (defun foo () t)
> FOO
> ? (setf function-name-1 'foo)
> FOO
> ? (setf function-name-2 '(lambda () t))
> (LAMBDA NIL T)
> ? (funcall function-name-1)
> T
> ? (funcall function-name-2)
>> Error: (LAMBDA NIL T) can't be FUNCALLed or APPLYed.

So this is where you trip over the function name vs function
designator distinction. The argument to FUNCALL is a function
designator, not a function name. So this is, technically speaking, not
a place you can use a function name thus does not contradict my claim.
Which is not to say that there isn't some operator in Common Lisp that
is documented to accept a function name but not a lambda expression,
but I can't think of any. (Moreover, it makes a certain logical sense
that there wouldn't be--the only two places that *have* to deal with
function names are the FUNCTION special operator and the basic
evaluation rule for function call forms. Everywhere else function
designators are a better choice since you can always use the FUNCTION
special operator to translate from names to function objects.

Pascal Bourguignon

unread,
Apr 22, 2006, 9:31:30 PM4/22/06
to
Peter Seibel <pe...@gigamonkeys.com> writes:

>> Nyms is not an english word as far as I can determine. (Remember,
>> we're talking about pedagogy here, so this is not a trivial detail.)
>
> I'm sorry if you didn't get the joke and doubly sorry if it actually
> confused you. Humour is always a tricky thing, but it can be a useful
> pedagogical tool. (Helps keep the student from falling asleep,
> drooling on your book, and getting the pages stuck to their face.)

It's only that nym is spelled name in English (nom in French, etc),
but it's still the same word.

--
__Pascal Bourguignon__ http://www.informatimago.com/

NOTE: The most fundamental particles in this product are held
together by a "gluing" force about which little is currently known
and whose adhesive power can therefore not be permanently
guaranteed.

Ron Garret

unread,
Apr 23, 2006, 1:46:53 AM4/23/06
to
In article <m2r73p9...@gigamonkeys.com>,
Peter Seibel <pe...@gigamonkeys.com> wrote:

> Ron Garret <rNOS...@flownet.com> writes:
>
> > Dictionary.com says that "eponym" means:
> >
> > 1 A person whose name is or is thought to be the source of the name
> > of something, such as a city, country, or era. For example, Romulus is
> > the eponym of Rome.
> > 2 Medicine. A name of a drug, structure, or disease based on or
> > derived from the name of a person.
> >
> > Accordingly, the above makes no sense to me.
>
> Well, it may be stretching the metaphor a bit but a lambda expression
> both is the function (i.e. it is Romulus) and it gives the function
> (what passes for) it's name.

But a lambda expression isn't a function. It is a list whose CAR is the
symbol LAMBDA. Lists aren't functions, at least not in CL. (Lists ARE
functions in e.g. NewLisp, which IMO is a Really Bad Idea (tm).)

> >> is perfectly consistent, i.e. anywhere you can use a function name
> >> to refer to a function you can also use a lambda expression.
> >
> > Not so:
> >
> > ? (defun foo () t)
> > FOO
> > ? (setf function-name-1 'foo)
> > FOO
> > ? (setf function-name-2 '(lambda () t))
> > (LAMBDA NIL T)
> > ? (funcall function-name-1)
> > T
> > ? (funcall function-name-2)
> >> Error: (LAMBDA NIL T) can't be FUNCALLed or APPLYed.
>
> So this is where you trip over the function name vs function
> designator distinction. The argument to FUNCALL is a function
> designator, not a function name. So this is, technically speaking, not
> a place you can use a function name thus does not contradict my claim.

There are two ways to interpret the claim "anywhere you can use a

function name to refer to a function you can also use a lambda
expression."

The first interpretation is: "Anywhere you can use *ANY* (object that
can serve as a) function name to refer to a function you can also use a
lambda expression."

The second interpretation is: "Anywhere the spec says you can use a
function name, you can also use a lambda expression."

Because the spec says that a lambda expression IS a function name, the
second interpretation is true by definition, which makes the claim
vacuous. Accordingly I assumed the first interpretation.

BTW (I'm sure you know this but just for the benefit of any lurkers out
there) there are actually FOUR distinct concepts in CL:

Functions
Function names
Function designators
Extended function designators

Discerning the differences between them is left as an exercise.

In any case, popping the stack a few frames, nothing you have said
dissuades me in any way from my belief that CL presents significant
pedagogical challenges.

rg

Kalle Olavi Niemitalo

unread,
Apr 23, 2006, 2:01:15 AM4/23/06
to
Ron Garret <rNOS...@flownet.com> writes:

> ? (defun (setf foo) () t)
> (SETF FOO)
> ? ((setf foo))
> Error: Car of ((SETF FOO)) is not a function name or lambda-expression.

CLISP returns T here, as an extension.
http://clisp.cons.org/impnotes.html#function-form

Thomas F. Burdick

unread,
Apr 23, 2006, 3:41:06 AM4/23/06
to
Ron Garret <rNOS...@flownet.com> writes:

> In article <m2zmid9...@gigamonkeys.com>,
> Peter Seibel <pe...@gigamonkeys.com> wrote:
>
> > Well the difference is that I'd say the treatment of lambda
> > expressions as function eponyms,
>
> Dictionary.com says that "eponym" means:

I think he really wanted to say something closer to autonym. Or at
least the French word "autonyme", since I can't find a reference in
English to autonym meaning a word designating itself (as it just did
there).

Curt

unread,
Apr 23, 2006, 8:00:03 AM4/23/06
to
On 2006-04-23, Thomas F. Burdick <t...@conquest.OCF.Berkeley.EDU> wrote:

>> Dictionary.com says that "eponym" means:
>
> I think he really wanted to say something closer to autonym. Or at
> least the French word "autonyme", since I can't find a reference in
> English to autonym meaning a word designating itself (as it just did
> there).
>

I googled this one:

http://www.fun-with-words.com/nym_words.html

Peter Seibel

unread,
Apr 23, 2006, 9:11:53 AM4/23/06
to
Ron Garret <rNOS...@flownet.com> writes:

> There are two ways to interpret the claim "anywhere you can use a
> function name to refer to a function you can also use a lambda
> expression."
>
> The first interpretation is: "Anywhere you can use *ANY* (object that
> can serve as a) function name to refer to a function you can also use a
> lambda expression."
>
> The second interpretation is: "Anywhere the spec says you can use a
> function name, you can also use a lambda expression."
>
> Because the spec says that a lambda expression IS a function name, the
> second interpretation is true by definition, which makes the claim
> vacuous. Accordingly I assumed the first interpretation.

Except the spec *doesn't* say a lambda expression is a function name.
That's my whole point.

> BTW (I'm sure you know this but just for the benefit of any lurkers out
> there) there are actually FOUR distinct concepts in CL:
>
> Functions
> Function names
> Function designators
> Extended function designators
>
> Discerning the differences between them is left as an exercise.

One easily solved by looking in the Hyperspec's glossary. For the lazy here it is:

Functions -- the actual function objects.

Function names -- symbols and lists of the form (SETF <symbol>)

Function designators -- symbols and lambda expressions

Extended function designators -- function names and lambda expressions

> In any case, popping the stack a few frames, nothing you have said
> dissuades me in any way from my belief that CL presents significant
> pedagogical challenges.

Oh, you don't have to tell *me* about CL's pedagogical challenges. Why
do you think it took me two years to write my book? But I think the
challenges, such as they are, come from two causes:

1) Many parts of Common Lisp are easy to understand but only if you
can grasp a few subtle ideas. Since subtle ideas are, well, subtle
they're hard to convey.

2) As a Lisp pedagog you can't count on your students cutting Lisp
any slack. Minor glitches and oddities, such as exist in any
language, are too often used as an excuse to give up on Lisp. When
writing Practical Common Lisp I took the approach of trying to
make the rewards of learning Lisp more obvious and working really
hard to find good ways to explain things.

What I found interesting was how often things that at first appeared
to fall in the glitches and oddities category would turn out to
actually be explicable in terms of some subtle idea. Unfortunately
that doesn't make them any easier to explain. Others, of course,
remain glitches and oddities no matter how you slice it. And even the
worst glitches in Common Lisp usually have some interesting history
behind them--often a history that teaches us lessons about how
computer languages are actually designed.

I do think folks who moan and groan all the time about how hard Lisp
is to teach or learn actually make the Lisp pedagog's job harder by
preconditiong would-be Lispers to beleive it's likely too hard for
them to learn. So ease up there. Or, to paraphrase Jon Stewart: "Stop
it, you're hurting Lisp."

Ron Garret

unread,
Apr 23, 2006, 1:06:28 PM4/23/06
to
In article <m2hd4ka...@gigamonkeys.com>,
Peter Seibel <pe...@gigamonkeys.com> wrote:

> Ron Garret <rNOS...@flownet.com> writes:
>
> > There are two ways to interpret the claim "anywhere you can use a
> > function name to refer to a function you can also use a lambda
> > expression."
> >
> > The first interpretation is: "Anywhere you can use *ANY* (object that
> > can serve as a) function name to refer to a function you can also use a
> > lambda expression."
> >
> > The second interpretation is: "Anywhere the spec says you can use a
> > function name, you can also use a lambda expression."
> >
> > Because the spec says that a lambda expression IS a function name, the
> > second interpretation is true by definition, which makes the claim
> > vacuous. Accordingly I assumed the first interpretation.
>
> Except the spec *doesn't* say a lambda expression is a function name.
> That's my whole point.

You're right. The spec says "lambda expression n. a list which can be
used in place of a function name in certain contexts." (I had forgotten
about the "in certain contexts" disclaimer, though I suppose technically
lambda expression still wouldn't BE function names even without it.)

So your claim is just flat-out false according to the spec. It is not
the case, according to the spec, that "anywhere you can use a function
name to refer to a function you can also use a lambda expression." It
is only true (according to the spec) "in certain contexts."

> > In any case, popping the stack a few frames, nothing you have said
> > dissuades me in any way from my belief that CL presents significant
> > pedagogical challenges.
>
> Oh, you don't have to tell *me* about CL's pedagogical challenges. Why
> do you think it took me two years to write my book? But I think the
> challenges, such as they are, come from two causes:
>
> 1) Many parts of Common Lisp are easy to understand but only if you
> can grasp a few subtle ideas. Since subtle ideas are, well, subtle
> they're hard to convey.

What subtle idea lies behind the distinction between functions, function
names, function designators and extended function designators? BTW,
there is actually a FIFTH concept as well: "a symbol naming a function",
which is introduced in section 3.1.2.1.2.3 in order to, as far as I can
tell, prevent ((setf ...) ...) from working as it intuitively should.
I've been studying this for 20 years and in all honesty it has always
just looked like a hack to me.

> 2) As a Lisp pedagog you can't count on your students cutting Lisp
> any slack. Minor glitches and oddities, such as exist in any
> language, are too often used as an excuse to give up on Lisp. When
> writing Practical Common Lisp I took the approach of trying to
> make the rewards of learning Lisp more obvious and working really
> hard to find good ways to explain things.
>
> What I found interesting was how often things that at first appeared
> to fall in the glitches and oddities category would turn out to
> actually be explicable in terms of some subtle idea. Unfortunately
> that doesn't make them any easier to explain.

In my experience, understanding the subtle idea behind apparent
complexity ALWAYS makes it easier to explain. (My favorite example is
http://www.flownet.com/ron/QM.pdf) Could you give an example where it
doesn't?

> Others, of course,
> remain glitches and oddities no matter how you slice it. And even the
> worst glitches in Common Lisp usually have some interesting history
> behind them--often a history that teaches us lessons about how
> computer languages are actually designed.

Living with those glitches forever is a high price to pay for a history
lesson IMO.

> I do think folks who moan and groan all the time about how hard Lisp
> is to teach or learn actually make the Lisp pedagog's job harder by
> preconditiong would-be Lispers to beleive it's likely too hard for
> them to learn. So ease up there. Or, to paraphrase Jon Stewart: "Stop
> it, you're hurting Lisp."

Long term improvement often requires some short term pain and sacrifice.
Sorry, but that's just the way the world is.

rg

Peter Seibel

unread,
Apr 23, 2006, 1:56:21 PM4/23/06
to
Ron Garret <rNOS...@flownet.com> writes:

Well, I tried--and probably failed--to draw a distinction there with
my use of "to refer to" to exclude the uses of function names in
definitional forms. As far as I know the only places in the language
that call for a function name (as opposed to a function designator of
some sort) are:

1. The second element of a FUNCTION form.

2. The first element of a list representing a function call form.

3. The second element of a DEFUN form.

4. The second first element of a function definition in a FLET and LABELS.

By "anywhere you can use a function name to refer to a function" I
meant to include 1 and 2 and exclude 3 and 4. That I didn't make that
distinction sufficiently clear is my fault. And it's possible that
there may be other places in the language that call for a function
name; if there are I'd love to be reminded what they are so I can see
if they fit into this analysis.

>> > In any case, popping the stack a few frames, nothing you have
>> > said dissuades me in any way from my belief that CL presents
>> > significant pedagogical challenges.
>>
>> Oh, you don't have to tell *me* about CL's pedagogical challenges. Why
>> do you think it took me two years to write my book? But I think the
>> challenges, such as they are, come from two causes:
>>
>> 1) Many parts of Common Lisp are easy to understand but only if you
>> can grasp a few subtle ideas. Since subtle ideas are, well, subtle
>> they're hard to convey.
>
> What subtle idea lies behind the distinction between functions, function
> names, function designators and extended function designators? BTW,
> there is actually a FIFTH concept as well: "a symbol naming a function",
> which is introduced in section 3.1.2.1.2.3 in order to, as far as I can
> tell, prevent ((setf ...) ...) from working as it intuitively should.
> I've been studying this for 20 years and in all honesty it has always
> just looked like a hack to me.

Well, sometimes the hacks are subtle. ;-) Seriously, in this
situation, there are two reasons, that things aren't nice and tidily
orthogonal.

1) It is desirable to be able to FUNCALL and APPLY globally defined
functions through a symbol. That is, those two functions (and
other functions that eventually FUNCALL or APPLY one of their
arguments) could have been defined to only take a proper function
rather than a function designator and to get the current behavior
we could always write:

(apply (if (symbolp fn) (symbol-function fn) fn) some-list)

instead of:

(apply fn some-list)

2) It is handy to be able to customize SETF via (defun (setf foo) ...)

The 1st point seems like a good design choice, though it adds a bit of
non-orthogonality to the langauge. And the 2nd is also a plesant
convenience that introduces the notion that a list of theform (SETF
<symbol>) is a "function name" in the sense of "a thing that can be
used as the second element of a DEFUN form". They *could* have gone
whole hog and made:

((setf foo) x)

another way of spelling:

(setf (foo) x)

But they didn't. I'm not even convinced that it would have been better
if they had--just another darn thing to explain, why there are these
two spellings for the same thing.

>> 2) As a Lisp pedagog you can't count on your students cutting Lisp
>> any slack. Minor glitches and oddities, such as exist in any
>> language, are too often used as an excuse to give up on Lisp. When
>> writing Practical Common Lisp I took the approach of trying to
>> make the rewards of learning Lisp more obvious and working really
>> hard to find good ways to explain things.
>>
>> What I found interesting was how often things that at first appeared
>> to fall in the glitches and oddities category would turn out to
>> actually be explicable in terms of some subtle idea. Unfortunately
>> that doesn't make them any easier to explain.
>
> In my experience, understanding the subtle idea behind apparent
> complexity ALWAYS makes it easier to explain. (My favorite example is
> http://www.flownet.com/ron/QM.pdf) Could you give an example where it
> doesn't?

I'd agree that understanding the subtle idea yourself *does* always
make it easier to explain. It may even be required before you can give
a proper explanation. But forcing your students/readers/conversational
partners/victims to understand the subtle idea as a prerequisite to
understanding the thing they actually want to know about is not always
a winning strategy, in my experience.

Ron Garret

unread,
Apr 23, 2006, 4:11:47 PM4/23/06
to
In article <m28xpw9...@gigamonkeys.com>,
Peter Seibel <pe...@gigamonkeys.com> wrote:

Well, I don't want to lose sight of the pedagogical forest by focusing
too much on the function name tree.

> >> > In any case, popping the stack a few frames, nothing you have
> >> > said dissuades me in any way from my belief that CL presents
> >> > significant pedagogical challenges.
> >>
> >> Oh, you don't have to tell *me* about CL's pedagogical challenges. Why
> >> do you think it took me two years to write my book? But I think the
> >> challenges, such as they are, come from two causes:
> >>
> >> 1) Many parts of Common Lisp are easy to understand but only if you
> >> can grasp a few subtle ideas. Since subtle ideas are, well, subtle
> >> they're hard to convey.
> >
> > What subtle idea lies behind the distinction between functions, function
> > names, function designators and extended function designators? BTW,
> > there is actually a FIFTH concept as well: "a symbol naming a function",
> > which is introduced in section 3.1.2.1.2.3 in order to, as far as I can
> > tell, prevent ((setf ...) ...) from working as it intuitively should.
> > I've been studying this for 20 years and in all honesty it has always
> > just looked like a hack to me.
>
> Well, sometimes the hacks are subtle. ;-) Seriously, in this
> situation, there are two reasons, that things aren't nice and tidily
> orthogonal.
>
> 1) It is desirable to be able to FUNCALL and APPLY globally defined
> functions through a symbol.

Why?

> That is, those two functions (and
> other functions that eventually FUNCALL or APPLY one of their
> arguments) could have been defined to only take a proper function
> rather than a function designator and to get the current behavior
> we could always write:
>
> (apply (if (symbolp fn) (symbol-function fn) fn) some-list)
>
> instead of:
>
> (apply fn some-list)

Right. So at best this hack saves you that bit of typing. I do not
mean to denigrate the benefit of saving a bit of typing, especially if
it's a very common idiom. But why is THAT bit of typing so much more
important than, e.g. this bit of typing:

(cond ((symbolp fn) (symbol-function fn))
((stringp fn) (symbol-function (intern fn)))
((and (consp fn) (eq (car fn) 'lambda)) (compile fn))
((and (consp fn) (eq (car fn) 'setf)) ...)
(t fn))

Note, by the way, that the preceding discussion is applicable ONLY if
you don't know what kind of object you have when you're writing the
code. If you know which you have then you don't need the conditional.
Now, I can't think of a single situation where you would not know at
code-writing time whether you have a symbol or a function object that
would not be the result of Really Bad Design (tm).

So I am still in the dark about the Subtle Idea hiding behind this mess.
Please enlighten me.

> 2) It is handy to be able to customize SETF via (defun (setf foo) ...)
>
> The 1st point seems like a good design choice,

Why?

> though it adds a bit of
> non-orthogonality to the langauge. And the 2nd is also a plesant
> convenience that introduces the notion that a list of theform (SETF
> <symbol>) is a "function name" in the sense of "a thing that can be
> used as the second element of a DEFUN form". They *could* have gone
> whole hog and made:
>
> ((setf foo) x)
>
> another way of spelling:
>
> (setf (foo) x)
>
> But they didn't. I'm not even convinced that it would have been better
> if they had--just another darn thing to explain, why there are these
> two spellings for the same thing.

Another thing they could have done is borrowed a page from the T
playbook and made (SETTER FOO) be the name of the setter function so as
not to overload the symbol SETF to be both a macro and the prelude for
certain kinds of function names. That would have made the two cases be:

((setter foo) ...)
(setf (foo) ...)

which could be understood without having to explain "another darn thing."

But they didn't.

> >> 2) As a Lisp pedagog you can't count on your students cutting Lisp
> >> any slack. Minor glitches and oddities, such as exist in any
> >> language, are too often used as an excuse to give up on Lisp. When
> >> writing Practical Common Lisp I took the approach of trying to
> >> make the rewards of learning Lisp more obvious and working really
> >> hard to find good ways to explain things.
> >>
> >> What I found interesting was how often things that at first appeared
> >> to fall in the glitches and oddities category would turn out to
> >> actually be explicable in terms of some subtle idea. Unfortunately
> >> that doesn't make them any easier to explain.
> >
> > In my experience, understanding the subtle idea behind apparent
> > complexity ALWAYS makes it easier to explain. (My favorite example is
> > http://www.flownet.com/ron/QM.pdf) Could you give an example where it
> > doesn't?
>
> I'd agree that understanding the subtle idea yourself *does* always
> make it easier to explain. It may even be required before you can give
> a proper explanation. But forcing your students/readers/conversational
> partners/victims to understand the subtle idea as a prerequisite to
> understanding the thing they actually want to know about is not always
> a winning strategy, in my experience.

In my experience, when that appears to be the case, you haven't really
understood it yourself (or perhaps you are just unwilling to face the
fact that what you thought was a Subtle Idea is really a Horrible Hack).

http://chronicle.com/jobs/v45/i47/4547ctlyst.htm

rg

Peter Seibel

unread,
Apr 23, 2006, 4:42:36 PM4/23/06
to
Ron Garret <rNOS...@flownet.com> writes:

>> 1) It is desirable to be able to FUNCALL and APPLY globally defined
>> functions through a symbol.
>
> Why?

Because it provides a level of indirection that allows code to pick up
changes in function definitions. Consider the difference between:

(funcall 'foo x y z)

and:

(funcall #'foo x y z)

in the face of a redefinition of FOO. Given that that kind of dynamic
redefinition is an import part of The Lisp Way, this seems like a
coherent design choice. (Yes, it is non-orthogonal. If you want a
language that more consistently strives for orthogonality Scheme is
over there. But I know you don't want Scheme so I assume you're not
really hung up on orthogonality for it's own sake.)

>> That is, those two functions (and
>> other functions that eventually FUNCALL or APPLY one of their
>> arguments) could have been defined to only take a proper function
>> rather than a function designator and to get the current behavior
>> we could always write:
>>
>> (apply (if (symbolp fn) (symbol-function fn) fn) some-list)
>>
>> instead of:
>>
>> (apply fn some-list)
>
> Right. So at best this hack saves you that bit of typing. I do not
> mean to denigrate the benefit of saving a bit of typing, especially if
> it's a very common idiom. But why is THAT bit of typing so much more
> important than, e.g. this bit of typing:
>
> (cond ((symbolp fn) (symbol-function fn))
> ((stringp fn) (symbol-function (intern fn)))
> ((and (consp fn) (eq (car fn) 'lambda)) (compile fn))
> ((and (consp fn) (eq (car fn) 'setf)) ...)
> (t fn))
>
> Note, by the way, that the preceding discussion is applicable ONLY if
> you don't know what kind of object you have when you're writing the
> code. If you know which you have then you don't need the conditional.
> Now, I can't think of a single situation where you would not know at
> code-writing time whether you have a symbol or a function object that
> would not be the result of Really Bad Design (tm).

See my example above. In both cases I know exactly what kind of object
I have at hand but the two expressions are not equivalent.

> So I am still in the dark about the Subtle Idea hiding behind this mess.
> Please enlighten me.

I think it's the old chestnut, "Any software problem can be solved
with another layer of indirection."

> Another thing they could have done is borrowed a page from the T
> playbook and made (SETTER FOO) be the name of the setter function so as
> not to overload the symbol SETF to be both a macro and the prelude for
> certain kinds of function names. That would have made the two cases be:
>
> ((setter foo) ...)
> (setf (foo) ...)
>
> which could be understood without having to explain "another darn thing."
>
> But they didn't.

No they didn't. Oh well.

>> I'd agree that understanding the subtle idea yourself *does* always
>> make it easier to explain. It may even be required before you can
>> give a proper explanation. But forcing your
>> students/readers/conversational partners/victims to understand the
>> subtle idea as a prerequisite to understanding the thing they
>> actually want to know about is not always a winning strategy, in my
>> experience.
>
> In my experience, when that appears to be the case, you haven't really
> understood it yourself (or perhaps you are just unwilling to face the
> fact that what you thought was a Subtle Idea is really a Horrible Hack).
>
> http://chronicle.com/jobs/v45/i47/4547ctlyst.htm

I certainly agree that the ability to explain something in terms the
average Joe can understand is a good measure of how well one
understands something. Indeed, that was the main pain I experienced
when writing my book--the constant nagging feeling that if I could
just grok this stuff one level deeper myself, that a better, shorter,
way to explain it would just pop out.

But that doesn't mean that the best way to approach every topic is to
start from first principles. The example I'm thinking of in
particular, that came up while writing in my book, is the way Lisp
splits apart READ and EVAL, exposing both bits. Once you get that the
reader is just responsible for translating text into Lisp objects and
that the semantics of Lisp are defined in terms of Lisp objects (and
that the basic evaluation rule is pretty straight-forward) you are
well on your way to understanding a lot Lisp and the way it's the way
it is. But it's not clear how soon you want to dive down to that
level, especially when it's so foreign to folks' prior experience.

Ron Garret

unread,
Apr 23, 2006, 9:16:09 PM4/23/06
to
In article <m2u08k8...@gigamonkeys.com>,
Peter Seibel <pe...@gigamonkeys.com> wrote:

> Ron Garret <rNOS...@flownet.com> writes:
>
> >> 1) It is desirable to be able to FUNCALL and APPLY globally defined
> >> functions through a symbol.
> >
> > Why?
>
> Because it provides a level of indirection that allows code to pick up
> changes in function definitions. Consider the difference between:
>
> (funcall 'foo x y z)
>
> and:
>
> (funcall #'foo x y z)
>
> in the face of a redefinition of FOO.

What difference would that be?

? (defun foo () 1)
FOO
? (funcall 'foo)
1
? (funcall #'foo)
1
? (defun foo () 2)
FOO
? (funcall 'foo)
2
? (funcall #'foo)
2
? (defun baz () (funcall #'foo))
BAZ
? (baz)
2
? (defun foo () 3)
FOO
? (baz)
3
?

Looks like the same behavior to me.


> But that doesn't mean that the best way to approach every topic is to
> start from first principles. The example I'm thinking of in
> particular, that came up while writing in my book, is the way Lisp
> splits apart READ and EVAL, exposing both bits. Once you get that the
> reader is just responsible for translating text into Lisp objects and
> that the semantics of Lisp are defined in terms of Lisp objects (and
> that the basic evaluation rule is pretty straight-forward) you are
> well on your way to understanding a lot Lisp and the way it's the way
> it is. But it's not clear how soon you want to dive down to that
> level, especially when it's so foreign to folks' prior experience.

We should probably start another thread if you really want to get into
this.

rg

Bill Atkins

unread,
Apr 23, 2006, 9:32:25 PM4/23/06
to
Ron Garret <rNOS...@flownet.com> writes:

Probably because this is being interpreted. If you were compiling
this, the (function foo) could be replaced with the actual address of
FOO, since it is known at compile-time; with just a symbol, it would
be necessary to find the function attached to FOO and then call that.

Peter Seibel

unread,
Apr 23, 2006, 9:36:48 PM4/23/06
to
Ron Garret <rNOS...@flownet.com> writes:

Sorry, my example was a bit off. I was thinking of this case:

CL-USER> (defun foo () 'first)
FOO
CL-USER> (defvar *foo-fn* #'foo)
*FOO-FN*
CL-USER> (defvar *foo-sym* 'foo)
*FOO-SYM*
CL-USER> (list (funcall *foo-fn*) (funcall *foo-sym*))
(FIRST FIRST)
CL-USER> (defun foo () 'second)
FOO
CL-USER> (list (funcall *foo-fn*) (funcall *foo-sym*))
(FIRST SECOND)

Peter Seibel

unread,
Apr 23, 2006, 9:39:48 PM4/23/06
to
Bill Atkins <NOatki...@rpi.edu> writes:

Actually no, that's not the issue: (function foo) behaves just like
(foo ...) as far is how and when the current function binding is
looked up. And it has to work this way because you can compile a
function that contains either kind of reference to a not-yet-defined
function.

The issue that I was getting at, which my original example didn't
demonstrate, has to do with when you store a reference to a function
or symbol in a variable and later pass the value of that variable to
FUNCALL. (See my other recent post in this thread for a full example.)

Ron Garret

unread,
Apr 24, 2006, 1:27:10 AM4/24/06
to
In article <m2hd4j9...@gigamonkeys.com>,
Peter Seibel <pe...@gigamonkeys.com> wrote:

Why not just do this then?

(defvar *foo-fn* (lambda () (foo)))

rg

Ari Johnson

unread,
Apr 24, 2006, 1:29:34 AM4/24/06
to
Ron Garret <rNOS...@flownet.com> writes:

> Why not just do this then?
>
> (defvar *foo-fn* (lambda () (foo)))

Probably because it completely misses the point, although the lack of
scalability could also be a factor.

Bill Atkins

unread,
Apr 24, 2006, 1:30:43 AM4/24/06
to
Ari Johnson <iamt...@gmail.com> writes:

In what way?

Ari Johnson

unread,
Apr 24, 2006, 1:58:32 AM4/24/06
to
Bill Atkins <NOatki...@rpi.edu> writes:

Having recently written software where this kind of thing matters,
specifically where a continuously-running thread was doing the
funcalling and I wanted to change the definition of the function it
was funcalling while it kept running, I am pretty certain that a
closure stored in a global variable is not the best way to do it,
especially in lieu of feeding the function that started the
long-running thread the name of a function to call and expecting it to
call that function by name even if you change its definition.

That is, you still end up feeding the long-running thread a symbol
that names a function to funcall, it's just a matter of whether you
feed it like A or like B:

A:
(start-server :handler 'handler)

B:
(defvar *handler-function* (lambda () (handler)))
(start-server)

Ron Garret

unread,
Apr 24, 2006, 2:05:45 AM4/24/06
to
In article <m2mzeb8...@hermes.theari.com>,
Ari Johnson <iamt...@gmail.com> wrote:

C:
(start-server :handler (lambda () (handler)))

rg

Ari Johnson

unread,
Apr 24, 2006, 2:09:13 AM4/24/06
to
Ron Garret <rNOS...@flownet.com> writes:

Should I be surprised that you like making code harder to read?

Ron Garret

unread,
Apr 24, 2006, 3:17:49 AM4/24/06
to
In article <m2iroz8...@hermes.theari.com>,
Ari Johnson <iamt...@gmail.com> wrote:

I don't see why my way is any hard to read than your option B. But if
you really don't like having that extra lambda in there you can always
define a reader macro so that you can type, e.g.:

(start-server :handler #"handler)

where #"foo expands to (lambda () (foo)).

rg

Ari Johnson

unread,
Apr 24, 2006, 11:17:17 AM4/24/06
to
Ron Garret <rNOS...@flownet.com> writes:

Or, in the alternative, I can just write 'handler. Is there a reason
you are opposed to doing things the easy way?

0 new messages