6.1.1 Macro Functions - naver/lispe GitHub Wiki

Macro Functions: defmacro

A macro is a function that is applied at compile time to replace a piece of code with another. Macro functions in LispE are based on the same principle as pattern programming as demonstrated with defpat functions.

A macro can be divided into different functions, each with its own set of parameters.

Note that the $ operator in macros are used both in the parameter list and as a macro operator in the code.

(defmacro name (P1...Pn) code)

A macro is a way to replace code with a more complex definition.

; this macro computes the cube of a number:

(defmacro cube(x) (* x x x))

If we apply this macro in a piece of code:

(cube 10)

cube will be replaced with its definition:

(* 10 10 10)

More Complicated Patterns

The patterns that are available for defpat are also available for defmacro.

(defmacro tantque (x $ z)
   (while x $ z)
)

(setq x 0)
(tantque (< x 11) (+= x 1) (println x))

The $ operator is used here twice.

  • In the pattern definition, it is used to extract the final list of elements.
  • In the function definition, it is used to insert the content of this final list into the code.

Let's compare with and without the $ in the macro body:

; Without the $
(defmacro tantque (x $ z)
   (while x z)
)

; the extended code is now:
; (note the surrounding list around  (+= x &) (println x)
(while (< x 11) ((+= x 1) (println x)))

; With the $
(defmacro tantque (x $ z)
   (while x $ z)
)

; the extended code is now:
(while (< x 11) (+= x 1) (println x)

Basically, the $ extends the code with the content of the list that was extracted by the pattern. Note that you can add elements after the $ z:

(defmacro tantque (x $ z)
   (while x $ z (println x))
)

Multiple patterns

You can also use multiple patterns to introduce some variety in your code:

; The only difference is how the range is created

; Here it is an upward range
(defmacro tang(('< x y) $ z)
   (loop x (range 0 y 1) $ z)
)

; Here the range is downward
(defmacro tang(('> x y) $ z)
   (loop x (range y 0 -1) $ z)
)

if we apply these macros to:

(defun tst1(x)
   (tang (< x 5) (println (* 2 x)))
)

(defun tst2(x)
   (tang (> x 5) (println (* 2 x)))
)

We get:

; The first function contains a "<" and matches with the first macro
(defun tst1 (x) (loop x (range 0 5 1) (println (* 2 x))))

; The second function contains a ">" and matches with the second macro
(defun tst2 (x) (loop x (range 5 0 -1) (println (* 2 x))))