At 09:52 AM 8/19/98 +0200, Michael Sperber [Mr. Preprocessor] wrote:
>>>>> "Craig" == Craig Lanning
<CraigL(a)internetx.net> writes:
Craig> At 11:08 AM 8/18/98 +0200, Michael Sperber [Mr. Preprocessor]
Craig> wrote: [ ... ]
Craig> Maintaining hygiene this way is not really much worse than writing the
Craig> macro in the first place.
Urmh, yes it is. So there :-)
>> Also, a macro might refer to bindings whose names are free in the
>> macro definition. There's no guarantee that you'll get the same
>> bindings for a use that you referred to at the point of definition.
Craig> Most of the macros that I write are used at top level so lexical bindings
Craig> aren't a big problem.
Yes they are, because the macro may refer to other toplevel lexical
bindings. I just posted (and corrected ...) and example about this.
If the macro is expanded at top level then there are no lexical bindings
between it and whatever binding it may reference at top level. Your
revised example had a lexical binding between the macro use and top level.
It seems to me (I may be wrong) Common Lispers inherently avoid
situations where a macro lead to binding problems precisely because
they lead to these problems.
This is probably a true statement (and part of why I am having so much
trouble understanding your point). After 12+ years of Zetalisp and Common
Lisp programming it's very difficult to step back from the only way you
have ever done something and look objectively at an alternative.
In Scheme, I write macros which would
cause problems in Common Lisp (but don't in Scheme) all the time.
Craig> I don't see how using macroexpand limits the complexity of macros that one
can
Craig> write. (c-sh-M expands one level, m-sh-M expands all levels) I use
macroexpand
Craig> to make sure that the macro expands into the code that I intended. Getting
Craig> the right things quoted can be very tricky.
Exactly. Which is why in the Scheme macro system, the macro
metalanguage is not the same as the object language. No quoting you
may get wrong.
That still doesn't explain how using macroexpand limits the complexity of the
macros that you can write.
There happen to be no hygiene issues here. (Good for you ... :-} )
So, no, hygiene per se would not have made it easier. However,
pattern matching (instead of using s-exprs to represent expressions)
would have saved you all the quasiquoting trouble.
Here's an example in Scheme (taken from the Scheme 48 distribution)
which doesn't use hygiene, but does use pattern matching. It defines
macros for defining records in a convenient syntactic form:
; Copyright (c) 1993, 1994 by Richard Kelsey and Jonathan Rees.
; Copyright (c) 1996 by NEC Research Institute, Inc. See file COPYING.
; This is JAR's define-record-type, which doesn't resemble Richard's.
; There's no implicit name concatenation, so it can be defined
; entirely using syntax-rules. Example:
; (define-record-type foo :foo
; (make-foo x y)
; foo? - predicate name is optional
; (x foo-x)
; (y foo-y)
; (z foo-z set-foo-z!))
(define-syntax define-record-type
(syntax-rules ()
((define-record-type ?id ?type
(?constructor ?arg ...)
(?field . ?field-stuff)
...)
(begin (define ?type (make-record-type '?id '(?field ...)))
(define ?constructor (record-constructor ?type '(?arg ...)))
(define-accessors ?type (?field . ?field-stuff) ...)))
((define-record-type ?id ?type
(?constructor ?arg ...)
?pred
?more ...)
(begin (define-record-type ?id ?type
(?constructor ?arg ...)
?more ...)
(define ?pred (record-predicate ?type))))))
; Straightforward version
(define-syntax define-accessors
(syntax-rules ()
((define-accessors ?type ?field-spec ...)
(begin (define-accessor ?type . ?field-spec) ...))))
(define-syntax define-accessor
(syntax-rules ()
((define-accessor ?type ?field ?accessor)
(define ?accessor (record-accessor ?type '?field)))
((define-accessor ?type ?field ?accessor ?modifier)
(begin (define ?accessor (record-accessor ?type '?field))
(define ?modifier (record-modifier ?type '?field))))
((define-accessor ?type ?field)
(begin))))
Note the absence of quasiquote/unquote/unquote-splicing.
Here's macro which makes use of hygiene:
(define-syntax define-for-each
(syntax-rules ()
((define-for-each foo-for-each foo-length foo-ref)
(define (foo-for-each proc v)
(let ((z (foo-length v)))
(do ((i (- z 1) (- i 1)))
((< i 0) #f)
(proc (foo-ref v i))))))))
Note that
(define-for-each bar-for-each (lambda (dummy) z) (lambda (dummy) i))
(admittedly a contrived use) does the right thing.
>> Let's say I have this:
>>
>> (defvar bar 23) [ I meant (setq bar 23) ]
>>
>> and I want to refer to bar (that is, the above binding) in a macro
>> body:
>>
>> (defmacro foo () 'bar)
>>
>> ... but I do:
>>
>> (let ((bar 42)) (foo))
>> => 42
>>
>> This violates lexical scoping.
Craig> I can't think of any practical use for this construct. When I
Craig> reference a global binding this way in a macro, it is because I
Craig> wanted to rebind it for other code within the body of the macro.
Then you're not referencing the same global binding. When I reference
a global binding within a macro's lexical scope, I want to reference
that binding. Period.
Macros do not really reference bindings. They alter the lexical environment
by making potentially complex substitutions.
--
Cheers =8-} Chipsy
Friede, Völkerverständigung und überhaupt blabla
Craig Lanning
E-Mail: CraigL(a)InternetX.net