开发者

Problem with macro behaviour in lisp

开发者 https://www.devze.com 2023-02-13 03:58 出处:网络
If in the REPL I do this: (dolist (x (1 2 3)) (print x)) then I get an error since in (1 2 3) the digit 1 is not a symbol or a lambda expr.

If in the REPL I do this:

(dolist (x (1 2 3))
  (print x))

then I get an error since in (1 2 3) the digit 1 is not a symbol or a lambda expr. If I do:

(dolist (x (list 1 2 3))
      (print x))
开发者_StackOverflow

then it works ok.

My question is why the following works:

REPL> (defmacro test (lst)
           (dolist (x lst)
             (print x)))
=> TEST
REPL> (test (1 2 3))
1
2
3
=>NIL

Why does dolist accept (1 2 3) when it is inside the macro definition but not when directly in the repl? The assumption:

"Since TEST is a macro ,it does not evaluate its arguments, so (1 2 3) is passed as is to the dolist macro. So dolist must complain like it does when it is passed (1 2 3) in the REPL"

is obviously wrong. But where?

UPDATE: Although the answers help clarify some misunderstandings with macros, my question still stands and i will try to explain why:

We have established that dolist evaluates its list argument(code blocks 1, 2). Well, it doesnt seem to be the case when it is called inside a macro definition and the list argument that is passed to it is one of the defined macro arguments(code block 3). More details: A macro, when called, does not evaluate its arguments. So my test macro, when it is called, will preserve the list argument and will pass it as it is to the dolist at expansion time. Then at expansion time the dolist will be executed (no backquotes in my test macro def). And it will be executed with (1 2 3) as argument since this is what the test macro call passed to it. So why doesnt it throw an error since dolist tries to evaluate its list argument, and in this case its list argument (1 2 3) is not evaluatable. I hope this clears my confusion a bit.


This form:

(defmacro test (lst)
  (dolist (x lst)
    (print x)))

defines a macro, which is a "code transformation function" which gets applied to a form using this macro at macro expansion time. So, after you have defined this macro, when you evaluate this expression:

(test (1 2 3))

it first gets read to this list:

(test (1 2 3))

Then, since Lisp reads test at the operator position, it gets macro-expanded by passing the argument, which is the literal list (1 2 3), to the macro expansion function defined above. This means that the following gets evaluated at macro-expansion time:

(dolist (x '(1 2 3))
  (print x))

So, at macro-expansion time, the three values get printed. Finally, the return value of that form is returned as the code to be compiled and executed. Dolist returns nil here, so this is the code returned:

nil

Nil evaluates to nil, which is returned.

Generally, such a macro is not very useful. See "Practical Common Lisp" by Peter Seibel or "On Lisp" by Paul Graham for an introduction to useful macros.


Update: Perhaps it is useful to recapitulate the order of reading, expanding, and evaluating Lisp code.

First, the REPL takes in a stream of characters: ( t e s t ( 1 2 3 ) ), which it assembles into tokens: ( test ( 1 2 3 ) ).

Then, this is translated into a tree of symbols: (test (1 2 3)). There may be so-called reader macros involved in this step. For example, 'x is translated to (quote x).

Then, from the outside in, each symbol in operator position (i.e., the first position in a form) is examined. If it names a macro, then the corresponding macro function is invoked with the code (i.e., the subtrees of symbols) that is the rest of the form as arguments. The macro function is supposed to return a new form, i.e. code, which replaces the macro form. In your case, the macro test gets the code (1 2 3) as argument, prints each of the symbols contained within (note that this is even before compile time), and returns nil, throwing its arguments away (the compiler never even sees your little list). The returned code is then examined again for possible macroexpansions.

Finally, the expanded code that does not contain any macro invocations anymore is evaluated, i.e. compiled and executed. Nil happens to be a self-evaluating symbol; it evaluates to nil.

This is just a rough sketch, but I hope that it clears some things up.


Your macro test does not return any code. And yes, macro arguments are not evaluated. If you want to see the same error, you have to define your macro as:

(defmacro test (lst) `(dolist (x ,lst) (print x)))


Generally when you have questions about macro expansions, referring to MACROEXPAND-1 is a great first step.

* (macroexpand-1 '(test (1 2 3)))

1 
2 
3 
NIL
T

IE, what is happening is that the actual expansion is that sequence of prints.

Nil is what is returned by DOLIST, and is the expanded code.


Macros get their arguments passed unevaluated. They may choose to evaluate them. dolist does that for its list argument. It works with an unquoted list passed in for lst in your macro test:

(defmacro test (lst)
  (dolist (x lst)
    (print x)))

That's because at macro-expansion time the dolist sees lst as its argument. So when it evaluates it, it gets the list (1 2 3).


lst is a variable, when expand macro test, it also mean eval dolist structure. the first step is to eval the form lst, will get the lisp object (1 2 3).

like follow example:

(defmacro test (a) (+ a 2))

(test 2) --> 4 ; mean invoke add function, and the first variable a binding a value 2.

0

精彩评论

暂无评论...
验证码 换一张
取 消