net@TUB.BITNET (Oliver Laumann) (05/25/88)
I would like to know how you would expect macros to work in Scheme or generally in a lexically scoped Lisp. (I'm not talking about a specific Scheme implementation here) Suppose Scheme supported something like ``define-macro'' with the same syntax as ``define'', so that you could, for instance, write (define-macro (incr x) `(set! ,x (+ ,x 1))) Now my question is whether macros are lexically scoped (like functions) or whether macro expansion is performed in a purely syntactic way. Consider the following example: (define x 1) (define-macro (m) x) (let ((x 2)) (m)) Would you expect that (m) evaluates to 1 or to 2? Yes, I know, if I had written (define-macro (m) 'x), it would evaluate to 2. However, in both Common Lisp (using a different syntax, of course) and C-Scheme, (m) returns 1 in the example above. Thus, it looks as if the first time the macro body is evaluated, the evaluation takes place in the lexical scope of the define-macro. Now consider a slighly more complex example: (define x 1) (let ((x 2)) (define-macro (m) x) (let ((x 3)) (m))) In both Common Lisp and C-Scheme, this evaluates to 1. My mind boggles. The macro is local to the outer let, why is the ``x'' inside the macro body bound to the global variable? Are macro always implemented like this (in lexically scoped Lisps)? If so, why? [I'm sorry, if the answer to my question is obvious; I'm new to Scheme and Lisp.] -- Regards, Oliver Laumann, Technical University of Berlin, Germany. ...!pyramid!tub!net or net@TUB.BITNET ...!mcvax!unido!tub!net
krulwich-bruce@CS.YALE.EDU (Bruce Krulwich) (05/26/88)
In article <8805251659.AA00682@tub.UUCP> net@TUB.BITNET (Oliver Laumann) writes: >Consider the following example: > (define x 1) > (define-macro (m) x) > (let ((x 2)) > (m)) >Would you expect that (m) evaluates to 1 or to 2? In both Common Lisp >(using a different syntax, of course) and C-Scheme, (m) returns 1 in the >example above. Thus, it looks as if the first time the macro body is >evaluated, the evaluation takes place in the lexical scope of the >define-macro. Rather, that the macro is evaluated in the lexical scope in which it was defined, just like regular functions. >Now consider a slighly more complex example: > (define x 1) > (let ((x 2)) > (define-macro (m) x) > (let ((x 3)) > (m))) >In both Common Lisp and C-Scheme, this evaluates to 1. T's DEFINE-SYNTAX does what you want in both of these cases, evaluating to 1 in the first case and 2 in the second case. Bruce Krulwich
cph@KLEPH.AI.MIT.EDU (Chris Hanson) (05/27/88)
Date: Wed, 25 May 88 18:59:30 +0200 From: Oliver Laumann <net%TUB.BITNET@MITVMA.MIT.EDU> Consider the following example: (define x 1) (define-macro (m) x) (let ((x 2)) (m)) in both Common Lisp (using a different syntax, of course) and C-Scheme, (m) returns 1 in the example above. You have an old version of C-Scheme. The current version (release 6 and later) gives an "unbound variable X" error while evaluating the last expression. Now consider a slighly more complex example: (define x 1) (let ((x 2)) (define-macro (m) x) (let ((x 3)) (m))) In both Common Lisp and C-Scheme, this evaluates to 1. Again, this produces an "unbound variable X" error in the current release. As one of several people who has thought about the issues you raise, I'll offer the following: 1. The semantics of special forms like `define-macro' is confusing. The naive interpretation of the meaning requires that a macro created this way should be closed in the environment in which it lexically appears. Unfortunately, that environment usually does not exist until run time, while for obvious reasons it is desirable that macros be closed at compile time. 2. C-Scheme has "solved" this problem by forcing all such macros to be closed in the global environment (actually, in a distinct child of the global environment). This alternate environment is guaranteed to exist at compile time, and under normal circumstances your other definitions won't interact with it. Thus, this explains the "unbound variable" errors. I say "solved" above because, rather than providing an acceptable solution, all we've really done is try to make it obvious when the user is confused about the closing environment. 3. My personal conclusion is that `define-macro' is a bad idea. I rarely, if ever, use it. C-Scheme provides facilities for explicitly constructing syntax tables (see the file "runtime/syntax.scm", procedures `make-syntax-table' and `syntax-table-define', and the special forms `macro' and `using-syntax') which do not have this problem. Using these facilities, the macros are closed in the environment in which they are loaded. They also appear in a different file from their references, thus reducing the confusion. 4. The R*RS committee is in the process of generating a "standard" macro facility. Keep tuned for more news.