Mike Manilone
Mike Manilone

Reputation: 590

Macro for more than 1 line of code

I'm learning the macro system of Common Lisp and suddenly found a problem

(defun hello () (format t "hello ~%")) 
(defun world () (format t "world ~%"))
(defmacro call-2-func (func1 func2)
  `(,func1)
  `(,func2))

(macroexpand-1 '(call-2-func hello world)) 
(WORLD) 
T

Well. Why can't I generate 2 LoC from only one macro? How can I work around? (progn will not work in a more complicated situation...)

Upvotes: 4

Views: 274

Answers (2)

9mjb
9mjb

Reputation: 583

It didn't seem clear in the stuff above, so let me add... yes you can return 2 lines of code from a macro, but remember functions and macros generally only return 1 value. You can compute multiple values in function, but it only returns the last value. This function below only returns value-2 (it still computes value-1, it does nothing with value-1).

(defun myfun () (compute-value-1) (compute-value-2))

If you want to return 2 values you can either wrap them in a list (or other structure), or you can use #'values to return more than one value.

In this case, your macro can only return one statement, unless you wrap multiple values in a list or use #'values. What it returns has to be proper lisp code too, and usually that is done with a PROGN

(defmacro call-2-func (func1 func2) `(PROGN (,func1) (,func2)))

If you used

(defmacro call-2-func (func1 func2) `(,func1) `(,func2))

Then your macro computes 2 values, but it only returns the last one. (as you see in your macroexpand above)

You can see this easily with a defun that computes 2 values but only returns the last one.

(defun myname () 1 2)

Using VALUES gets a little weird.

(defmacro tttt () '(values (one) (one)))
(tttt)
1
1

Upvotes: 0

finnw
finnw

Reputation: 48619

Your macro needs to return just one form that will call both functions.
Instead you are generating two forms (and only the last one is used.)

Try:

(defmacro call-2-func (func1 func2)
  `(progn (,func1) (,func2)))

or if you do not want to be limited to just 2 functions:

(defmacro call-funcs (&rest funcs)
  `(progn ,@(mapcar #'list funcs)))

Upvotes: 10

Related Questions