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!
A macro is an ordinary piece of Lisp code that operates on another piece of putative Lisp code, translating it into (a version closer to) executable Lisp.
During a macroexpansion phase, the Lisp expression will be passed to the macro function. This macro function can do arbitrary computation at macroexpansion time. The result of this call has to be again Lisp code. This Lisp code then is what the interpreter or compiler sees and executes or compiles.
A binding is a pairing of an identifier with a location in which a Lisp object may be placed.
that takes arguments and returns a LISP form to be evaluated. It is useful when the same code has to be executed with a few variable changes. For example, rather than writing the same code for squaring a number, we can define a macro that holds the code for squaring.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With