Lexical Bindings in Common Lisp Macros
Asked Answered
L

1

5

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 on setq must be a macro which expands into a setq, rather than a function which calls it. Likewise for operators like let, whose arguments are to appear as parameters in a lambda expression, for macros like do which expand into lets, 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!

Lemuellemuela answered 12/3, 2018 at 21:53 Comment(3)
As an experience Lisper, I totally understand what that text is trying to say, only I cannot parse the actual text. If I run my finger down the middle of the paragraph and just skim it in 0.5 seconds, then it makes sense, but if I pick at the individual words and phrases then it sort of eludes me.Mcnair
The "arguments" of a let do not appear in a lambda expression, for instance. What?Mcnair
Are you saying it is poorly written? This paragraph was an example of a paragraph that no matter how many times I had read it, I still asked myself, "Whaaat?"Lemuellemuela
K
8

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.

Kaiserism answered 12/3, 2018 at 22:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.