1

I have following code which confuse me now, I hope some can tell me the difference and how to fix this.

(defmacro tm(a)
   `(concat ,(symbol-name a)))

(defun tf(a)
       (list (quote concat) (symbol-name a)))

I just think they should be the same effect, but actually they seem not.
I try to following call:

CL-USER> (tf 'foo)
(CONCAT "FOO")

CL-USER> (tm 'foo)
value 'FOO is not of the expected type SYMBOL.
[Condition of type TYPE-ERROR]

So, what's the problem?

What i want is:

(tm 'foo)  ==>  (CONCAT "FOO")
winterTTr
  • 1,739
  • 1
  • 10
  • 30

2 Answers2

4

The first problem is that 'foo is expanded by the reader to (quote foo), which is not a symbol, but a list. The macro tries to expand (tm (quote foo)). The list (quote foo) is passed as the parameter a to the macro expansion function, which tries to get its symbol-name. A list is not a valid argument for symbol-name. Therefore, your macro expansion fails.

The second problem is that while (tm foo) (note: no quote) does expand to (concat "FOO"), this form will then be executed by the REPL, so that this is also not the same as your tf function. This is not surprising, of course, because macros do different things than functions.

Svante
  • 50,694
  • 11
  • 78
  • 122
2

First, note that

`(concat ,(symbol-name a))

and

(list (quote concat) (symbol-name a))

do the exact same thing. They are equivalent pieces of code (backquote syntax isn't restricted to macro bodies!): Both construct a list whose first element is the symbol CONCAT and whose second element is the symbol name of whatever the variable A refers to.

Clearly, this only makes sense if A refers to a symbol, which, as Svante has pointed out, isn't the case in the macro call example.

You could, of course, extract the symbol from the list (QUOTE FOO), but that prevents you from calling the macro like this:

(let ((x 'foo))
  (tm x))

which raises the question of why you would event want to force the user of the macro to explicitly quote the symbol where it needs to be a literal constant anyway.

Second, the way macros work is this: They take pieces of code (such as (QUOTE FOO)) as arguments and produce a new piece of code that, upon macroexpansion, (more or less) replaces the macro call in the source code. It is often useful to reuse macro arguments within the generated code by putting them where they are going to be evaluated later, such as in

(defmacro tm2 (a)
  `(print (symbol-name ,a)))

Think about what this piece of code does and whether or not my let example above works now. That should get you on the right track.

Finally, a piece of advice: Avoid macros when a function will do. It will make life much easier for both the implementer and the user.

Matthias Benkard
  • 15,497
  • 4
  • 39
  • 47
  • Yes, I think maybe I should choose the function than macro at first. Thanks for your suggestion and answer. – winterTTr Jul 02 '11 at 01:20