Edit me

Macros

Macros#

Macros are functions that take code as input and return transformed code as output. A macro is like a function that is executed at compile time. They are useful to extend the syntax of the language itself.

Phel's core library itself uses macro to define the language. For example defn is as macro.

(defn add [a b] (+ a b))

is transformed to

(def add (fn [a b] (+ a b)))

Quote#

The quote operator is a special form, it returns its argument without evaluating it. Its purpose is to prevent any evaluation. Preceding a form with a single quote is a shorthand for (quote form).

(quote my-sym) # Evaluates to my-sym
'my-sym # Shorthand for (same as above)

Quote make macros possible, since its helps to distinguish between code and data. Literals like numbers and string evaluate to themselves.

(quote 1) # Evaluates to 1
(quote hi) # Evaluates the symbol hi
(quote quote) # Evaluates to the symbol quote

'(1 2 3) # Evaluates to the list (1 2 3)
'(print 1 2 3) # Evaluates to the list (print 1 2 3). Nothing is printed.

Define a macro#

(defmacro docstring? attributes? [params*] expr*)

The defmacro function can be used to create a macro. It takes the same parameters as defn.

Together with quote and defmacro, it is now possible to define a custom defn, which is called mydefn:

(defmacro mydefn [name args & body]
  (list 'def name (apply list 'fn args body)))

This macro is very simple at does not support all the feature of defn. But it illustrates the basics of a macro.

Quasiquote#

For better readability of marcos the quasiquote special form is defined. It turns the definition of macros around. Instead of quoting values that should not be evaluated, quasiquote marks values that should be evaluated. Every other value is not evaluated. A shorthand for quasiquote is the ` character. Values that should be evaluated are marked with the unquote function (shorthand ,) or unquote-splicing function (shorthand ,@). With quasiquote the mydefn macro can be expressed as

(defmacro mydefn [name args & body]
  `(def ,name (fn ,args ,@body)))