Meta-programming on Lisp

April 22, 2009 at 8:39 pm (Lisp)

Meta-programming is a powerfull technique, that allows you to manipulate your code as data, you can ask yourself “How the hell does this work exactly?”, meta-programming looks confusing but after you understand how it works your question can be change to “How to work without this?”.

Lisp is the most famous meta-programming language, it’s so natural working with this technique on Lisp.

Let’s see a simple recursive factorial algorithm, here we could use meta-programming to help us understand how this recursive function works, lisp has a trace macro that shows up step-by-step the code execution:

CL-USER> (defun factorial (x)
          (if (zerop x) 1 (* x (factorial (- x 1)))))

CL-USER> (factorial 3)

CL-USER> (trace factorial)
;; Tracing function FACTORIAL.

CL-USER> (factorial 6)
1. Trace: (FACTORIAL '6)
2. Trace: (FACTORIAL '5)
3. Trace: (FACTORIAL '4)
4. Trace: (FACTORIAL '3)
5. Trace: (FACTORIAL '2)
6. Trace: (FACTORIAL '1)
7. Trace: (FACTORIAL '0)
7. Trace: FACTORIAL ==> 1
6. Trace: FACTORIAL ==> 1
5. Trace: FACTORIAL ==> 2
4. Trace: FACTORIAL ==> 6
3. Trace: FACTORIAL ==> 24
2. Trace: FACTORIAL ==> 120
1. Trace: FACTORIAL ==> 720

The trace macro changes in execution time the factorial code to print the function steps, now we can have an idea on how to apply meta-programming in real world examples.

Now let’s implement a macro to simulate a for statement:

(defmacro for (var start stop &body body)
  (let ((gstop (gensym)))
    `(do ((,var ,start (1+ ,var))
          (,gstop ,stop))
         ((> ,var ,gstop))

Lisp has macroexpand-1 to show the code generated for a macro, therefore:

(macroexpand-1 '(for i 10 20 (print i)))


(DO ((I 10 (1+ I)) (#:G4588 20))
      ((> I #:G4588))  (PRINT I))

You can see how macros are powerful, allowing you to build sctrutctures easily, and extend the language to satisfy your need.

Wrapping up, meta-programming puts your code to work for you, think about it.

Permalink 1 Comment