4

Little help here please . I am trying to create this lisp macro which takes a list (of numbers) as input and returns the sum of those numbers. The code

(setf g (list 1 2 3 4))

(defmacro add-test(var)
    `(+ ,@var))

(add-test g) gives this error

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

At the same time (add-test (1 2 3 4)) gives the correct result which is 10.

Can you please explain , why is it not working when variable is passed in to the function?

Other details -

Lispbox - SBCL

Ubuntu Linux

Thanks in advance

1 Answer 1

10

That's easy and one of the most common macro questions.

(add-test g)

Now on macro expansion, the macro ADD-TEST is called with the parameter VAR getting the value G, a symbol.

Then you try a list operation. The backquote expression

`(+ ,@var)

The value of VAR is G, and you try to splice that into the list (+ ... ). Now the returned expression is (+ . G).

CL-USER 12 > (macroexpand '(add-test g))
(+ . G)
T

(+ . G) is not a valid Lisp form. It's not valid source code.

Remember, the parameters to a Macro are the unevaluated source expressions.

Compare that with the following:

CL-USER 13 > (macroexpand '(add-test (1 2 3 4)))
(+ 1 2 3 4)
T

You said: 'Can you please explain, why is it not working when variable is passed in to the function?'

Remember, ADD-TEST is NOT a function, it is a macro. A macro gets the source code passed and returns a new form - that form is then later evaluated.

Sign up to request clarification or add additional context in comments.

7 Comments

Thanks Rainer for the detailed answer. That helped a lot.
Out of curiosity, let's say we take bdev's idea further. Suppose I have some sort of optimizable expression (a list of integers!), and I want to optimize the expression prior to "run-time". How would I do that? (although I suppose (eval G) might work...).
@Paul Nathan: you can EVAL it, COMPILE it, FUNCALL it, APPLY it - there are almost no limits. See also DEFINE-COMPILER-MACRO, which allows you to write optimizations.
@Rainer - I finally found the solution for this - (defmacro add-test(x) `(+,@(evalx))) Thanks again for explaining this.
@Paul - Thanks for the 'eval' tip.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.