Tutorials

Creating Macros

Macros are a flexible way to define new language constructs within the language. This tutorial implements a for-each loop as an example.

First, let’s define the form of our for-each loop:

(for target in vector expression)

target is the name of the symbol, vector is the sequence we’re iterating through, and expression being the actions performed for every iteration.

We can use the macro function to define this form:

(macro for [target in vector expression]
       (do (setn vector (eval vector))
           (setn index 0)
           (setn final (len vector))
           (loop (when (= index final) (break))
                 (setr target (at index vector))
                 (eval expression)
                 (setn index (+ index 1)))))

Analysing this example, two procedures are to be observed, specifically, the use of setr and eval. First, the vector that is passed to the macro contains unevaluated expressions that first have to be evaluated using eval. As described by the form that we’ve written earlier, target is the name of the symbol that we’re assigning to, and as such, we’ll have to use setr instead of setn to make sure that we’re not binding using target literally. We then evaluate the expression literal, which has access to the value bound to target.

Let’s test it out on the REPL:

> (macro for [target in vector expression]
|        (do (setn vector (eval vector))
|            (setn index 0)
|            (setn final (len vector))
|            (loop (when (= index final) (break))
|                  (setr target (at index vector))
|                  (eval expression)
|                  (setn index (+ index 1)))))
for
> (for x in [1 2 3 4 5]
|      (print (* x x)))
1
4
9
16
25
:NIL

The newly defined for macro is able to iterate through the vector, binding each number to x before evaluating the expression.

Note: Macros create their own closure, and symbols bound within them are inaccessible after evaluation.

Modifying the macro to return the expression evaluated last is left as an exercise for the reader.