------------------------------------------------------------------------------
MC logo
Toms Lisp Macro Definitions
[^] Tom's Lisp
------------------------------------------------------------------------------
[Basic Input Format] [Lists, Pairs and Related Operations] [Conditional Evaluation] [Basic Function Definition] [Definitions and Scope] [Functions Which Take Functions] [String Functions] [Exception Handling] [Quoting And Evaluation] [Variable-Length Parameter Lists] [Macro Definitions] [Printing] [The Tomslsp command and its switches] [Index of Standard Functions]

Macros are similar to functions, and are created with a similar syntax:

(macro parameterlist body)
Macros are created with the macro operator and named using setq. There's no nice convenient define for macros. (Though you could write a macro to create one.)

The difference between macros and functions is in the details of evaluation. Here's how macro calls are evaluated. (You may want to compare this to function evaluation here). A macro call:

  1. Enters a new scope, but stacks it atop the one where the function was created, not where it was called.
  2. Binds the unevaluated argument values to the parameter names in this new scope.
  3. Evaluates the macro body.
  4. Leaves the scope.
  5. Evaluates the result of the macro body in the calling context. This result is the value of the macro call.
A macro is able to rearrange its arguments before they are evaluated. For instance, the initialization file defines setq as follows:
(set 'setq 
    (macro (n v) 
        (list 'set (list 'quote n) v)
    )
)
When you evaluate
(setq fred 17)
the setq macro body is run with n and v bound to the unevaluated arguments fred and 17. This produces
(set (quote fred) 17)
which is then evaluated in the caller's context. It is access to the unevaluated arguments that makes a macro special.

Macros heavily used in the initialization file. For instance, the standard if construct is defined in terms of the built-in cons as follows:

(setq if (macro form 
    (list 'cond (list (car form) (cadr form))
                (cond ((cddr form) (list #t (caddr form))) ())  )
))
It's a mess to read, but it just takes in the arguments to if (all passed as the single list form), and produces an equivalent cond. This is then evaluated.

Production Lisps generally have something called quasiquote which makes it easier to construct the lists macros must create. Tom's isn't that fancy.