macros and hygiene, resumed
The Friday entry demonstrates how to break hygiene for a macro that defines a generator. Ryan Culpepper, the local macrologist, reminded me that expanding into this macro goes wrong in the syntax-case world:
(define-syntax define-that-expands-into-define/y (syntax-rules () ((_ (name arg ...) body ...) (define/y (name arg ...) body ...)))) (define-that-expands-into-define/y (bar) (yield 1) (yield 2) 'finished)
datum->syntax-object
is the syntactic context of the new macro but it doesn't bind yield; it just uses it. So the definition of yield
in define/y
must be a different one according to the hygiene standards. Ergo yield is free at the top-leve [MzScheme] or bound to the yield import from MrEd [Pretty Big].
;; ---
How can we try to fix this? The explanation suggests we use a different macro definition for define/y
, one that uses a context that is guaranteed from the body of an instance of define/y
:
(require (lib "control.ss")) (define-syntax (define/y stx) (syntax-case stx () [(_ (name arg ...) body0 body ...) (with-syntax ((yield-name (datum->syntax-object (syntax body0) 'yield))) (syntax (define (name arg ...) (define (yield-name x) (control resume-here (set! name (lambda () (prompt (resume-here 'dummy)))) x)) (prompt body0 body ...))))])) (define-syntax define-that-expands-into-define/y (syntax-rules () ((_ (name arg ...) body ...) (define/y (name arg ...) body ...)))) ;; --- try it out --- (define-that-expands-into-define/y (bar) (yield 1) (yield 2) 'finished) (list (bar) (bar) (bar) (bar))
3 comments:
Isn't it still a problem that we cannot use yield in macros?
As a silly example:
(define-syntax yield2
(syntax-rules (yield)
((_ x) (yield x))))
(define/y (step)
(yield2 1)
'finished))
We'll get a yield unbound error when calling step.
Ah, OK, this has to do with the lexical scope of yield.
If I define
(define/y (step)
(define-syntax yield2
(syntax-rules ()
((_ x) (yield x))))
(yield2 1)
'finished)
instead, it works.
Post a Comment