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

Macro Question

31 views
Skip to first unread message

Blaine

unread,
May 26, 2006, 12:46:11 PM5/26/06
to
Hi,

I'm having trouble understanding macro parameters. In the following, I
don't understand why macrotest1 compiles and yields the desired output
while macrotest2, when called with mylst, doesn't compile.

(defmacro mac (expr)
`(pprint (macroexpand-1 ',expr)))

(setf mylst '(10 20 30 40))

(defmacro macrotest1 ()
`(list
(+ 3 4)
,@(loop for i in (list 10 20 30 40) collect `(+ ,i ,i))
(- 4 3)))

(defmacro macrotest2 (lst)
`(list
(+ 3 4)
,@(loop for i in lst collect `(+ ,i ,i))
(- 4 3)))

> (mac (macrotest1))

(LIST (+ 3 4) (+ 10 10) (+ 20 20) (+ 30 30) (+ 40 40) (- 4 3))
; No value
> (mac (macrotest2 mylst))

The value MYLST is not of type LIST.
[Condition of type TYPE-ERROR]

Surely, mylst is a list. And furthermore, when I call macrotest2 with
something that is not a list - at least I don't think it's a list - it
works.

> (mac (macrotest2 (10 20 30 40)))

(LIST (+ 3 4) (+ 10 10) (+ 20 20) (+ 30 30) (+ 40 40) (- 4 3))
; No value

Currently I have four lisp books open to their respective macro
chapters, and I'm still at a loss. This macro stuff is tough. Help is
much appreciated.

Thank you,
Blaine

Aaron Sokoloski

unread,
May 26, 2006, 12:58:42 PM5/26/06
to
Hi Blaine,

When (macrotest2 mylst) is called, it binds the argument lst to the
symbol 'mylst, which, as LISP says, is "not of type LIST". When you
call it with with (10 20 30 40), it receives the list '(10 20 30 40),
which works exactly the same as macrotest1. Remember that macros don't
evaluate their arguments. I think you're expecting mylst to be
evaluated.

Is there something in particular you're trying to do? Or is this just
a learning exercise?

Blaine

unread,
May 26, 2006, 1:48:44 PM5/26/06
to
Hi Aaron,

Thanks much for the quick reply.

Indeed, there is something I'm trying to do. I want a function (not
sure if that's the right word) whose guts change at compile time in
accordance with some pre-specified information.

So, given:

(setf pre-spec-info '((A 2)(B 1)(C 1)(D 3)))
(setf mysym 'B)

I want the call (mymacro mysym pre-spec-info)
to expand into:

(cond
((eql sym 'A) 2)
((eql sym 'B) 1)
((eql sym 'C) 4)
((eql sym 'D) 3)
(t (error "sym not found")))

and return:

1

The pre-spec-info variable, I take it, is going to be the problem. If
it is never evaluated, there is no way to get at the needed
information... Perhaps a macro isn't the answer?

Aaron Sokoloski

unread,
May 26, 2006, 2:26:17 PM5/26/06
to
> So, given:
>
> (setf pre-spec-info '((A 2)(B 1)(C 1)(D 3)))
> (setf mysym 'B)
>
> I want the call (mymacro mysym pre-spec-info)
> to expand into:
>
> (cond
> ((eql sym 'A) 2)
> ((eql sym 'B) 1)
> ((eql sym 'C) 4)
> ((eql sym 'D) 3)
> (t (error "sym not found")))
>
> and return:
>
> 1
>
> The pre-spec-info variable, I take it, is going to be the problem. If
> it is never evaluated, there is no way to get at the needed
> information... Perhaps a macro isn't the answer?

Hmm. You've got two options that I can think of (and I'm definitely
not a guru here).

One, you can always call mymacro like this:

(mymacro B ((a 2) (b 1) (c 4) (d 3))

but I don't think that's what you want -- blech. The other is to do
something like this:

(eval-when (:compile-toplevel :load-toplevel :execute)
(defvar *pre-spec-info* '((A 2)(B 1)(C 1)(D 3)))

which will make sure that the global var *pre-spec-info* is ready when
the macro is expanded. By the way, I'm not sure if :execute is needed
- try taking it out once things are working.

In any case, your macro will be able to use *pre-spec-info*, and its
value will be the alist '((A 2)(B 1)(C 1)(D 3)), so it should work ok.

Another issue: what your macro should do depends on what information
you have. If you know the value of the symbol mysym at compile time,
you can actually make the macro simply expand to 2, 1, 4, or 3 or give
an error -- all at compile time (that is, you can just evaluate the
cond at compile time). On the other hand, if the symbol could vary at
run time, then it makes sense to expand it the way you described. I
think this second case is what's going on, am I right?

Aaron

Tayssir John Gabbour

unread,
May 26, 2006, 2:36:00 PM5/26/06
to
Blaine wrote:
> So, given:
>
> (setf pre-spec-info '((A 2)(B 1)(C 1)(D 3)))
> (setf mysym 'B)
>
> I want the call (mymacro mysym pre-spec-info)
> to expand into:
>
> (cond
> ((eql sym 'A) 2)
> ((eql sym 'B) 1)
> ((eql sym 'C) 4)
> ((eql sym 'D) 3)
> (t (error "sym not found")))
>
> and return:
>
> 1

Hi Blaine,

The typical idiom is to use ASSOC:

(assoc 'b '((A 2)(B 1)(C 1)(D 3)))
=> (b 1)

And you can put in whatever errorhandling you desire:

(defun my-function (item alist)
(let ((result (assoc item alist)))
(unless result (error "~S not found in ~S" item alist))
(second result)))


CL-USER> (my-function 'b '((A 2)(B 1)(C 1)(D 3)))
1
CL-USER> (my-function 'f '((A 2)(B 1)(C 1)(D 3)))
ERROR: F not found in ((A 2) (B 1) (C 1) (D 3))
[Condition of type SIMPLE-ERROR]


> The pre-spec-info variable, I take it, is going to be the problem. If
> it is never evaluated, there is no way to get at the needed
> information... Perhaps a macro isn't the answer?

Yes, you'll probably be a happier person if you use macros just for
things like control flow, where you really might want new syntax. Your
example is the sort of thing much more cleanly done with functions;
extra scrutiny is useful before reaching for defmacro.

Tayssir

Pascal Bourguignon

unread,
May 26, 2006, 2:58:11 PM5/26/06
to
"Blaine" <jillan...@hotmail.com> writes:
> I'm having trouble understanding macro parameters. In the following, I
> don't understand why macrotest1 compiles and yields the desired output
> while macrotest2, when called with mylst, doesn't compile.

The first thing to understand with lisp macros, is that backquote and
comma don't have anything to do with macros!

The second thing to understand is that lisp macros are lisp functions
like any other function.

That's all. When you've understood those two points, you've
understood 98% there is to understand about lisp macros.

Now, for the first point, let's try out backquote and comma.
- Try to guess what these expressions would result to,
- then copy and paste these expressions to the REPL

(let ((lst '(1 2 3)))
(list (quote a) (quote list) (quote lst)))

(let ((lst '(1 2 3)))
`(a list lst))

(let ((lst '(1 2 3)))
(list (quote a) (quote list) lst))

(let ((lst '(1 2 3)))
`(a list ,lst))

(let ((lst '(1 2 3)))
(list* (quote a) (quote list) lst))

(let ((lst '(1 2 3)))
`(a list ,@lst))


(let ((lst '(1 2 3)))
(list (quote a) (quote list) (quote lst) (quote in-the) (quote middle)))

(let ((lst '(1 2 3)))
`(a list lst in-the middle))

(let ((lst '(1 2 3)))
(list (quote a) (quote list) lst (quote in-the) (quote middle)))

(let ((lst '(1 2 3)))
`(a list ,lst in-the middle))

(let ((lst '(1 2 3)))
(append (list(quote a)(quote list)) lst (list(quote in-the)(quote middle))))

(let ((lst '(1 2 3)))
`(a list ,@lst in-the middle))


Seen a macro so far?

On to the second point, macros are functions exactly like any other
function.


Let's say we want a function that takes a list ( ... i ...) of numbers
as argument and return a form like:

(list (+ 3 4) ... (+ i i) ... (- 4 3))

How can we write such a function?

(defun fun-test-2 (list)
(append
(list (quote list) (quote (+ 3 4)))
(mapcar (lambda (i) (list (quote +) i i)) list)
(list (quote (- 4 3)))))

Let's try it:

(fun-test-2 '(10 20 30 40 50))
--> (LIST (+ 3 4) (+ 10 10) (+ 20 20) (+ 30 30) (+ 40 40) (+ 50 50) (- 4 3))

Is this exactly what you wanted? Ok.

So now, it remains on to find a way to tell the compiler that when we write:

(macrotest2 (10 20 30 40 50))
it must compile:
(LIST (+ 3 4) (+ 10 10) (+ 20 20) (+ 30 30) (+ 40 40) (+ 50 50) (- 4 3))
instead.

This is done as:

(defmacro macrotest2 (list) (fun-test-2 list)) ; the next to last 1%

Simple enough!

Let's check the compiler will see the right form;

(macroexpand-1 '(macrotest2 (10 20 30 40 50)))
--> (LIST (+ 3 4) (+ 10 10) (+ 20 20) (+ 30 30) (+ 40 40) (+ 50 50) (- 4 3)) ;
T

Ok. Let's try to run it:

(macrotest2 (10 20 30 40 50))
--> (7 20 40 60 80 100 1)

Now, note the last 1%: when you call a macro, the arguments are not
evaluated. It behaves like if all the arguments where put inside
(quote ...) before calling the function.


[36]> (trace fun-test-2)
;; Tracing function FUN-TEST-2.
(FUN-TEST-2)
[37]> (macrotest2 (10 20 30 40 50)) ; you write (10 ... 50)
1. Trace: (FUN-TEST-2 '(10 20 30 40 50)) ; the func. is called with '(10 ... 50)
; which evaluates to (10 ... 50)
1. Trace: FUN-TEST-2 ==> (LIST (+ 3 4) (+ 10 10) (+ 20 20) (+ 30 30) (+ 40 40) (+ 50 50) (- 4 3))
(7 20 40 60 80 100 1)


So, obviously, if you call: (macrotest2 lst)
what the macro will get bound to its argument list is the symbol lst,
not the value of the symbol lst:

[38]> (macrotest2 lst)
1. Trace: (FUN-TEST-2 'LST)
*** - MAPCAR: A proper list must not end with LST

If you want to accept such parameters, and therefore you want to
evalate them, you must:

1- think about not using a macro, but a function:

(let ((lst '(10 20 30 40 50)))
(fun-test-2 lst))
works perfectly, returning:
(LIST (+ 3 4) (+ 10 10) (+ 20 20) (+ 30 30) (+ 40 40) (+ 50 50) (- 4 3))

Of course, if what you want is the list of the sums, not an form to
build the list of the sums, you should write the function accordingly:

(defun fun-test-3 (list)
(append (list (+ 3 4))
(mapcar (lambda (i) (+ i i)) list)
(list (- 4 3))))

(let ((lst '(10 20 30 40 50)))
(fun-test-3 lst))
--> (7 20 40 60 80 100 1) ; See? No need for a macro!


2- if you insist to use a macro, go back to 1.

3- if you really need a macro, you must consider when the variable lst is
created and bound, and when it is to be evaluated.

Macros are executed at macro-expansion time. This may occur at
during compilation time, or before run-time, or somewhen else.
That means that if the value of variable you pass as argument is
not known before run-time, there's no way the macro can guess what
the value will be: perhaps the program will be run in two months,
two years, or never.

Are you sure you don't want to point 1?

So, it may be a variable that you've created and bound at
compilation time, for use by the macro, at macro-expansion time.
You could write it as:

(eval-when (:compile-toplevel :load-toplevel :execute)

(defparameter *lst* '(10 20 30 40 50)))

(defmacro macro-test-3 (name-of-variable)
(append
(list (quote list) (quote (+ 3 4)))
(mapcar (lambda (i) (list (quote +) i i))
(symbol-value name-of-variable))
(list (quote (- 3 4)))))

(macro-test-3 *lst*) --> (7 20 40 60 80 100 -1)
(macroexpand-1 '(macro-test-3 *lst*))
--> (LIST (+ 3 4) (+ 10 10) (+ 20 20) (+ 30 30) (+ 40 40) (+ 50 50) (- 3 4)) ;
T


But of course, it's not possible to get the run-time value of a
variable to use it at macro-expansion time like this:

(let ((lst '(1 2 3 4 5)))
(macro-test-3 lst))
*** - SYMBOL-VALUE: LST has no dynamic value

You should go back to point 1!

Still here? Well, we cannot evaluate the variable denoted by the
argument of the macro, but we can insert it into a form to be
executed at run-time that will use its value, at run-time:

We will generate something like:

(append (list (+ 3 4))
(mapcar (lambda (i) (+ i i)) <name-of-variable>)
(list (- 3 4)))

(defmacro macro-test-4 (name-of-variable)
(list (quote append)
(quote (list (+ 3 4)))
(list (quote mapcar)
(quote (lambda (i) (+ i i)))
name-of-variable)
(quote (list (- 3 4)))))

(macroexpand-1 '(macro-test-4 lst))
--> (APPEND (LIST (+ 3 4)) (MAPCAR (LAMBDA (I) (+ I I)) LST)
(LIST (- 3 4))) ;
T

(macro-test-4 lst)
*** - EVAL: variable LST has no value ; of course.

(let ((lst '(1 2 3 4 5)))
(macro-test-4 lst))
--> (7 2 4 6 8 10 -1)

But then, why write a macro? Wouldn't it be simplier to write a
mere function like in point 1? Go to point 1 check it!


Well, finally, you can test at macroexpansion time whether you
have a variable name or a literal list, and generate a different
expansion accordingly:

(defmacro macro-test-5 (argument)
(if (symbolp argument)
(list (quote append)
(quote (list (+ 3 4)))
(list (quote mapcar)
(quote (lambda (i) (+ i i)))
argument)
(quote (list (- 3 4))))
(append
(list (quote list) (quote (+ 3 4)))
(mapcar (lambda (i) (list (quote +) i i))
argument)
(list (quote (- 3 4))))))

So you can write :

(macroexpand-1 '(macro-test-5 (10 20 30 40 50)))
--> (LIST (+ 3 4) (+ 10 10) (+ 20 20) (+ 30 30) (+ 40 40) (+ 50 50) (- 3 4)) ;
T
(macroexpand-1 '(macro-test-5 lst))
--> (APPEND (LIST (+ 3 4)) (MAPCAR (LAMBDA (I) (+ I I)) LST) (LIST (- 3 4))) ;
T

But then, (no don't go to point 1, but still not a MACRO), you
should have written a function (for the normal case with a run-time
variable), and a COMPILER-MACRO to optimize out the case when the
argument is literal data. Read HyperSpec about: DEFINE-COMPILER-MACRO

In conclusion, macros are not hammers that render all the problems
nails. It's a delicate high-tech tool to be used only in the rare
occasion when it's really indicated.


NB1: Of course, you can use backquote and comma instead of append, list,
cons, etc:

(defun fun-test-2 (list)
(append
(list (quote list) (quote (+ 3 4)))
(mapcar (lambda (i) (list (quote +) i i)) list)
(list (quote (- 4 3)))))
-->
(defun fun-test-2 (list)
`(list (+ 3 4)
,@(mapcar (lambda (i) `(+ ,i ,i)) list)
(- 3 4)))

NB2: And of course, as with any function, you can substitute the bodyn
of a called function in place of the function call:

(defun fun-test-2 (list)
`(list (+ 3 4)
,@(mapcar (lambda (i) `(+ ,i ,i)) list)
(- 3 4)))

(defmacro macrotest2 (list) (fun-test-2 list))

can be written:

(defmacro macrotest2 (list)
`(list (+ 3 4)
,@(mapcar (lambda (i) `(+ ,i ,i)) list)
(- 3 4)))

But this is nothing specific to the macro functions.

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

"Logiciels libres : nourris au code source sans farine animale."

Tayssir John Gabbour

unread,
May 26, 2006, 3:41:42 PM5/26/06
to
A bit of clarification...


Blaine wrote:
> Indeed, there is something I'm trying to do. I want a function (not
> sure if that's the right word) whose guts change at compile time in
> accordance with some pre-specified information.

Yes, you know how Lisp users program in sexps? Macros are sexp -> sexp
transformers.

When mymacro sees this:
(mymacro mysym pre-spec-info)

it sees the sexps MYSYM and PRE-SPEC-INFO. It doesn't see what the Lisp
system evaluates those sexps into later.

I think Joe Marshall said it interestingly:
"Variables abstract over values, functions abstract over behavior,
macros abstract over syntax."
http://groups.google.com/group/comp.lang.lisp/msg/d05bfebe3822d1cb


Tayssir

Peter Seibel

unread,
May 26, 2006, 3:45:04 PM5/26/06
to
"Blaine" <jillan...@hotmail.com> writes:

> Currently I have four lisp books open to their respective macro
> chapters, and I'm still at a loss. This macro stuff is tough. Help is
> much appreciated.

Just out of curiosity: what four books?

-Peter

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

Blaine

unread,
May 26, 2006, 6:27:49 PM5/26/06
to
Pascal,

Your reply has helped me significantly. Thank you.

In particular, your 3rd option, which I repeat here, gets me where I
want to be:

(eval-when (:compile-toplevel :load-toplevel :execute)
(defparameter *lst* '(10 20 30 40 50)))

(defmacro macro-test-3 (name-of-variable)
(append
(list (quote list) (quote (+ 3 4)))
(mapcar (lambda (i) (list (quote +) i i))
(symbol-value name-of-variable))
(list (quote (- 3 4)))))

(macro-test-3 *lst*) --> (7 20 40 60 80 100 -1)
(macroexpand-1 '(macro-test-3 *lst*))
--> (LIST (+ 3 4) (+ 10 10) (+ 20 20) (+ 30 30) (+ 40 40) (+ 50 50)
(- 3 4)) ;

It has enabled me to write a prototype of what I really want. Here's
the prototype:

(eval-when (:compile-toplevel :load-toplevel :execute)

(defparameter *util-scheme* '(('A 1) ('B 2) ('C 2))))

(defmacro generic-utility (util-scheme mysym)
(append (list 'cond)
(mapcar (lambda (i) `((eql ,mysym (first (list ,@i)))
(second (list ,@i))))
(symbol-value util-scheme))
(list `(t (error "no match")))))

CL-USER> (mac (generic-utility *util-scheme* 'B))
--->
(COND ((EQL 'B (FIRST (LIST 'A 1))) (SECOND (LIST 'A 1)))
((EQL 'B (FIRST (LIST 'B 2))) (SECOND (LIST 'B 2)))
((EQL 'B (FIRST (LIST 'C 2))) (SECOND (LIST 'C 2)))
(T (ERROR "no match")))
; No value

The *util-scheme* variable that I want to use in the non-prototype is
more complex. When fed to the future generic-utility macro, the macro
will yield more complex condition statements. There will be nested
conditions and a bunch of arithmetic in the final expansion. The
program I'm writing will call generic-utility alot (maybe more than any
other call), so I think having it expand once-and-for-all before
run-time is good. (Does this last sentence make sense?)

Thanks again,
Blaine

PS The series of exercises at the beginning helped too!

Blaine

unread,
May 26, 2006, 6:39:08 PM5/26/06
to
Peter,

The books are:

1. ANSI Common Lisp
2. Successful Lisp
3. On Lisp (pdf)
and
4. Yours

Please take no offense; macros, at least for me, are tough.

Pascal's point, "The first thing to understand with lisp macros, is
that backquote and comma don't have anything to do with macros!", is
one that I believe you make in your book (I don't have it with me). I
just didn't get it until Pascal beat it into me with his series of
exercises.

-Blaine

Thomas A. Russ

unread,
May 26, 2006, 6:57:43 PM5/26/06
to
"Blaine" <jillan...@hotmail.com> writes:

> Hi,
>
> I'm having trouble understanding macro parameters. In the following, I
> don't understand why macrotest1 compiles and yields the desired output
> while macrotest2, when called with mylst, doesn't compile.

This has to do with when various things are done in Lisp.
In this case, one has to distinguish between runtime and macroexpansion
time. One also needs to be aware of what the value of the arguments
are.

> (setf mylst '(10 20 30 40))

OK, here you set the symbol MYLST to a list of numbers.

> (defmacro macrotest1 ()
> `(list
> (+ 3 4)
> ,@(loop for i in (list 10 20 30 40) collect `(+ ,i ,i))
> (- 4 3)))

The LOOP code executes at macroexpansion time. In other words, the loop
needs to be able to execute when the macro expands.

> (defmacro macrotest2 (lst)
> `(list
> (+ 3 4)
> ,@(loop for i in lst collect `(+ ,i ,i))
> (- 4 3)))

Here the LOOP code also executes at macroexpansion time. When this code
expands, the macro argument LST is bound to the argument to the macro.
In other words, LST is bound to whatever CODE you put in as the argument.

> > (mac (macrotest2 mylst))
>
> The value MYLST is not of type LIST.
> [Condition of type TYPE-ERROR]

In this call, LST is bound to the SYMBOL MYLST. That is because macros
DO NOT EVALUATE THEIR ARGUMENTS. This is the key thing that you need to
remember. Unlike in a function call, in a macroexpansion, MYLST is not
evaluated before being bound to LST. Instead the code (in this case
just a single symbol) is what is bound to LST.

> Surely, mylst is a list. And furthermore, when I call macrotest2 with
> something that is not a list - at least I don't think it's a list - it
> works.

Nope. MYLST is a symbol. It is bound to a list, but the binding is
irrelevant, since the argument isn't evaluated.


> > (mac (macrotest2 (10 20 30 40)))

Well, (10 20 30 40) certainly looks like a list to me. You will perhaps
notice that there is no need to quote the list, since macros don't
evaluate their arguments.

>

> (LIST (+ 3 4) (+ 10 10) (+ 20 20) (+ 30 30) (+ 40 40) (- 4 3))
> ; No value
>
> Currently I have four lisp books open to their respective macro
> chapters, and I'm still at a loss. This macro stuff is tough. Help is
> much appreciated.

Try the following much simpler macro and see if it helps you understand
this a bit better:

(defmacro teach (arg)
(format t "At macroexpansion time, ARG = ~S of type ~A~%"
arg (type-of arg))
`(list arg ,arg))

(macroexpand '(teach mylst))
(macroexpand '(teach (10 20 30 40)))


--
Thomas A. Russ, USC/Information Sciences Institute

Peter Seibel

unread,
May 26, 2006, 9:22:29 PM5/26/06
to
"Blaine" <jillan...@hotmail.com> writes:

So you're probably in good shape now. If not, I'd suggest taking the
time to read all the way through chapters 7 and 8 of PCL. There's
nothing too terribly hard about macros but there are a few key points
that you have to pick up or you'll wrap yourself around the axel. I
tried to hit on all those points in those chapters but you have to
make sure you're eagerness to get going doesn't lead you to skip over
them. Or maybe my explanation didn't just make sense to you; that's
always a possibility.

Blaine

unread,
May 28, 2006, 6:42:01 PM5/28/06
to
Thomas,

Nice example. Thanks.

Quick follow-up question. (10 20 30 40) most definately looks like a
list, but is it?

If I enter (listp (10 20 30 40)) at the REPL I get the following:

EVAL: 10 is not a function name
[Condition of type SYSTEM::SIMPLE-SOURCE-PROGRAM-ERROR]

I'm not being flip - this is actually something that's bugged me for a
while. '(10 20 30 40) is a list. (list 10 20 30 40) is a list, but
(10 20 30 40) isn't? It seems, somehow, not right (or at least
strange).

Again, thank you,
Blaine

Pascal Bourguignon

unread,
May 28, 2006, 6:57:00 PM5/28/06
to
"Blaine" <jillan...@hotmail.com> writes:

"(10 20 30 40)" is the external representation of a list. It _is_ a list.

Now, when you give the REPL some list to be evaluated, you must follow
some rules. EVAL takes a FORM as argument, not a random LIST.

A form is an atom, or a list whose first element is the name of a
function, macro or special operator.

10 is not the name of a function, macro or special operator, therefore
(10 20 30 40) is not a valid FORM to give to EVAL.


Try this:

(LISTP (READ))
(10 20 30 40)

Then:

(LISTP (READ-FROM-STRING "(10 20 30 40)"))

Then:

(EVAL (READ))
(QUOTE (10 20 30 40))

Then:

(EVAL (QUOTE (QUOTE (10 20 30 40))))

Then:

(EVAL (QUOTE (LISTP (QUOTE (10 20 30 40)))))

Then:

(EVAL (READ))
(LISTP (QUOTE (10 20 30 40)))

Then:

(LISTP (QUOTE (10 20 30 40)))
;; Remember that the REPL includes its own Read and Eval,
;; in addition to its Print and Loop.

Finally:

(LIST 10 20 30 40)

And:

(LISTP (LIST 10 20 30 40))

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

There is no worse tyranny than to force a man to pay for what he does not
want merely because you think it would be good for him. -- Robert Heinlein

Blaine

unread,
May 30, 2006, 8:16:22 AM5/30/06
to
I get it. Thanks!

Thomas A. Russ

unread,
May 30, 2006, 1:37:55 PM5/30/06
to
"Blaine" <jillan...@hotmail.com> writes:

> Thomas,
>
> Nice example. Thanks.
>
> Quick follow-up question. (10 20 30 40) most definately looks like a
> list, but is it?

Yes.

> If I enter (listp (10 20 30 40)) at the REPL I get the following:
>
> EVAL: 10 is not a function name
> [Condition of type SYSTEM::SIMPLE-SOURCE-PROGRAM-ERROR]
>
> I'm not being flip - this is actually something that's bugged me for a
> while. '(10 20 30 40) is a list.

Yes it is, but not the list you think it is. It is in fact the list

(QUOTE (10 20 30 40))

The ' character is just a Lisp reader shortcut for wrapping (QUOTE ... )
around an expression. In fact

'foo

is also the list (QUOTE FOO).

Now what is getting you confused is again the issue of evaluation of
arguments. LISTP is a function, and so it evaluates its arguments. The
rules of evaluation for a list is to apply the first element
(interpreted as a function) to the values of the remainin elements. If
you want to stop such evaluation, you have to quote the argument.
Evaluation of a quoted argument returns the value that has been quoted.
In other words, evaluation removes one level of quotation, or
equivalently, quotation inhibits one level of evaluation.

This is a fundamental concept that you will need to master in order to
do well in lisp programming.

> (list 10 20 30 40) is a list, but
> (10 20 30 40) isn't? It seems, somehow, not right (or at least
> strange).

These are both lists.

The first one also evaluates into a list, since the first element names
a function. It also happens to be a function that creates a list.

The second cannot be evaluated, since the first element does not name a
function.

If you try

(vector 10 20 30 40 50)

you will have a list that evaluates into a vector rather than a list.

>
> Again, thank you,
> Blaine

As for your larger purpose, I don't think you really want to use a macro
to solve it. I think that you would do well to use ordinary functions.
It seems that some combination of ASSOC or the CASE features will likely
do what you want to do.

By encapsulating your conditional dispatch code in a function, you
already avoid the need to repeat it everywhere. I usually find it much
more convenient to have my source code all in one place rather than to
put some of it in a global variable and then have it transformed by some
other piece of code.

Thomas A. Russ

unread,
May 30, 2006, 1:38:40 PM5/30/06
to
"Blaine" <jillan...@hotmail.com> writes:

> Thomas,
>
> Nice example. Thanks.
>
> Quick follow-up question. (10 20 30 40) most definately looks like a
> list, but is it?

Yes.

> If I enter (listp (10 20 30 40)) at the REPL I get the following:
>
> EVAL: 10 is not a function name
> [Condition of type SYSTEM::SIMPLE-SOURCE-PROGRAM-ERROR]
>
> I'm not being flip - this is actually something that's bugged me for a
> while. '(10 20 30 40) is a list.

Yes it is, but not the list you think it is. It is in fact the list

(QUOTE (10 20 30 40))

The ' character is just a Lisp reader shortcut for wrapping (QUOTE ... )
around an expression. In fact

'foo

is also the list (QUOTE FOO).

Now what is getting you confused is again the issue of evaluation of
arguments. LISTP is a function, and so it evaluates its arguments. The
rules of evaluation for a list is to apply the first element
(interpreted as a function) to the values of the remainin elements. If
you want to stop such evaluation, you have to quote the argument.
Evaluation of a quoted argument returns the value that has been quoted.
In other words, evaluation removes one level of quotation, or
equivalently, quotation inhibits one level of evaluation.

This is a fundamental concept that you will need to master in order to
do well in lisp programming.

> (list 10 20 30 40) is a list, but


> (10 20 30 40) isn't? It seems, somehow, not right (or at least
> strange).

These are both lists.

The first one also evaluates into a list, since the first element names
a function. It also happens to be a function that creates a list.

The second cannot be evaluated, since the first element does not name a
function.

If you try

(vector 10 20 30 40 50)

you will have a list that evaluates into a vector rather than a list.

>
> Again, thank you,
> Blaine

As for your larger purpose, I don't think you really want to use a macro
to solve it. I think that you would do well to use ordinary functions.
It seems that some combination of ASSOC or the CASE features will likely
do what you want to do.

By encapsulating your conditional dispatch code in a function, you
already avoid the need to repeat it everywhere. I usually find it much
more convenient to have my source code all in one place rather than to
put some of it in a global variable and then have it transformed by some
other piece of code.

--

Thomas A. Russ

unread,
May 30, 2006, 1:39:41 PM5/30/06
to
"Blaine" <jillan...@hotmail.com> writes:

> Thomas,
>
> Nice example. Thanks.
>
> Quick follow-up question. (10 20 30 40) most definately looks like a
> list, but is it?

Yes.

> If I enter (listp (10 20 30 40)) at the REPL I get the following:
>
> EVAL: 10 is not a function name
> [Condition of type SYSTEM::SIMPLE-SOURCE-PROGRAM-ERROR]
>
> I'm not being flip - this is actually something that's bugged me for a
> while. '(10 20 30 40) is a list.

Yes it is, but not the list you think it is. It is in fact the list

(QUOTE (10 20 30 40))

The ' character is just a Lisp reader shortcut for wrapping (QUOTE ... )
around an expression. In fact

'foo

is also the list (QUOTE FOO).

Now what is getting you confused is again the issue of evaluation of
arguments. LISTP is a function, and so it evaluates its arguments. The
rules of evaluation for a list is to apply the first element
(interpreted as a function) to the values of the remainin elements. If
you want to stop such evaluation, you have to quote the argument.
Evaluation of a quoted argument returns the value that has been quoted.
In other words, evaluation removes one level of quotation, or
equivalently, quotation inhibits one level of evaluation.

This is a fundamental concept that you will need to master in order to
do well in lisp programming.

> (list 10 20 30 40) is a list, but


> (10 20 30 40) isn't? It seems, somehow, not right (or at least
> strange).

These are both lists.

The first one also evaluates into a list, since the first element names
a function. It also happens to be a function that creates a list.

The second cannot be evaluated, since the first element does not name a
function.

If you try

(vector 10 20 30 40 50)

you will have a list that evaluates into a vector rather than a list.

>
> Again, thank you,
> Blaine

As for your larger purpose, I don't think you really want to use a macro
to solve it. I think that you would do well to use ordinary functions.
It seems that some combination of ASSOC or the CASE features will likely
do what you want to do.

By encapsulating your conditional dispatch code in a function, you
already avoid the need to repeat it everywhere. I usually find it much
more convenient to have my source code all in one place rather than to
put some of it in a global variable and then have it transformed by some
other piece of code.

--

0 new messages