I am currently working my way through Graham's On Lisp and find this particular bit difficult to understand:
Binding. Lexical variables must appear directly in the source code. The first argument to
setq
is not evaluated, for example, so anything built onsetq
must be a macro which expands into asetq
, rather than a function which calls it. Likewise for operators likelet
, whose arguments are to appear as parameters in a lambda expression, for macros like do which expand intolet
s, and so on. Any new operator which is to alter the lexical bindings of its arguments must be written as a macro.
This comes from Chapter 8, which describes when macros should and should not be used in place of functions.
What exactly does he mean in this paragraph? Could someone give a concrete example or two?
Much appreciated!
setq
is a special form and does not evaluate its first argument. Thus if you want to make a macro that updates something, you cannot do it like this:
(defun update (what with)
(setq what with))
(defparameter *test* 10)
(update *test* 20) ; what does it do?
*test* ; ==> 10
So inside the function update
setq
updates the variable what
to be 20
, but it is a local variable that has the value 10
that gets updated, not *test*
itself. In order to update *test*
setq
must have *test*
as first argument. A macro can do that:
(defmacro update (what with)
`(setq ,what ,with))
(update *test* 20) ; what does it do?
*test* ; ==> 20
You can see exactly the resulting code form the macro expansion:
(macroexpand-1 '(update *test* 20))
; ==> (setq *test* 20) ; t
A similar example. You cannot mimic if
with cond
using a function:
(defun my-if (test then else)
(cond (test then)
(t else)))
(defun fib (n)
(my-if (< 2 n)
n
(+ (fib (- n 1)) (fib (- n 2)))))
(fib 3)
No matter what argument you pass you get an infinite loop that always call the recursive case since all my-if
arguments are always evaluated. With cond
and if
the test
gets evaluated and based on that either the then
or else
is evaluated, but never all unconditionally.