[gambit-list] eval order, define vs define-macro
Marc Feeley
feeley at iro.umontreal.ca
Thu May 11 11:17:26 EDT 2006
On 11-May-06, at 10:38 AM, Stephane Le Cornec wrote:
> (define (foo x) x)
> (define-macro (bar x) `(+ ,x ,(foo x)))
> (define (baz x) (bar x))
>
>> (load "test")
> *** ERROR IN #<procedure #2>, "test.scm"@2.1 -- Unbound variable: foo
> 1>
>
> I was a little surprised of the result. OTOH:
>
> (define (baz2 x) (bar2 x))
> (define-macro (bar2 x) `(+ ,x 2))
>
> fails on (baz2 2) as expected while the reverse works properly.
>
>
> I don't understand why the eval order does not work for define-
> macro. Is the behavior an implementation choice? And if so why is
> it wanted?
Assume the following code is in the file "test.scm":
(define (foo x) x)
(define-macro (bar x) `(+ ,x ,(foo x)))
(define (baz x) (bar x))
and you compile this code with
gsc -dynamic test.scm
and then run the code with
gsi test.o1
Ask yourself when the variables foo and baz will be set.
The answer is at run time, that is when gsi loads the file test.o1 .
On the other hand the macro bar must be known at compile time (also
known as expansion time), that is when gsc compiles the file
test.scm, because the definition of baz depends on the expansion that
results from calling the macro bar. But in your code, the definition
for bar depends on foo which is only known at run time. That's why
foo is not defined when you call bar in baz.
For consistency with the compiler, the interpreter has the same
semantics. It also has an expansion time and a run time, but these
are two separate phases (i.e. expansion of the source code is
completely done, then the interpreter runs the code).
Because it can't really do otherwise, the REPL evaluates each form
individually (i.e. expansion and then run, for each expression
entered). So if you type those 3 definitions at the REPL it will
work, because when you enter the definition for baz, the function foo
has been defined.
Does that clarify things?
The reason why this is counterintuitive is that macros give the
illusion that function definitions and macro definitions are
evaluated in the same "world". Although the same language is used,
there are really two worlds: the run time world and the expansion
time world. This makes it hard to write macros that need to share
some expansion time function or state. Here's one way to achieve this.
(define-macro (at-expand-time expr) (eval expr) `(begin))
(at-expand-time (define (foo x) x))
(define-macro (bar x) `(+ ,x ,(foo x)))
(define (baz x) (bar x))
Marc
More information about the Gambit-list
mailing list