[plt-scheme] moving macros from top-level to module-level
Hi ho PLTers-
I'm trying to do some macro hackery, and I developed a macro that has a
desired behavior at the top level, but ceases to retain that behavior
after being shifted into its own module and then provided from that
module.
I have a rough understanding of what MzScheme is doing and why things
are failing, but I don't know how to make the provided DEFINE-LAZY act
like it does at the top level. The standard tricks (like giving up
automatic hygiene and using DATUM->SYNTAX-OBJECT to produce the desired
forms in the "right" namespace) do not seem to be working.
Any advice?
-Felix
p.s.
Here is the code at the top-level Also, after the top-level code
(which "works"), I've included the module that has three attempts to
provide DEFINE-LAZY, all of which cause failures (for the first, the
DEFINE-LAZY form itself fails, while for the other two, the usage of
the macros/procedures defined by DEFINE-LAZY form is what fails).
p.p.s
As an aside, I think DEFINE-LAZY demonstrates an interesting usage of
SYNTAX-ID-RULES that does not use the SET! feature of that macro
definition form.
----------------------- TOP LEVEL -----------------------
(define-syntax define-lazy
(syntax-rules ()
[(define-lazy (OP ARG ...) BODY ...)
(begin
(define (function ARG ...)
(let-syntax
((ARG (syntax-id-rules ()
[(_ RANDS (... ...))
((force ARG) RANDS (... ...))]
[_
(force ARG)]))
...)
BODY ...))
(define-syntax OP
(syntax-rules ()
[(OP ARG ...)
(function (delay ARG) ...)])))]
))
;; Sample usage:
;; (new-if #t 1 (/ 1 0)) ==> 1
(define-lazy (new-if test then else)
(if test then else))
(new-if #t 1 (/ 1 0))
----------------------- MODULE LEVEL -----------------------
(module lazy mzscheme
(provide define-lazy/1 define-lazy/2 define-lazy/3)
;; I'm trying to run these test cases on the base form:
#|
(begin
(require (lib "lazy.scm" "util"))
(define-lazy/3 (stream-cons x y) (cons x (delay y)))
(stream-cons 1 2))
|#
;; Note that the first form, DEFINE-LAZY/1 works if you insert it at
;; the top level (at least for doing experiments at the top-level)
;; while the second form, DEFINE-LAZY/2, fails in the same manner at
;; the top-level that it does when provided from a module
;; Attempt One, fails with:
;; define-values: identifier for a top-level definition already has a
module context at: function in: (define-values (function) (lambda (x y)
(let-syntax ((x (syntax-id-rules () ((_ rands ...) ((forc...
(define-syntax define-lazy/1
(syntax-rules ()
[(define-lazy (OP ARG ...) BODY ...)
(begin
(define (function ARG ...)
(let-syntax
((ARG (syntax-id-rules ()
[(_ RANDS (... ...))
((force ARG) RANDS (... ...))]
[_
(force ARG)]))
...)
BODY ...))
(define-syntax OP
(syntax-rules ()
[(OP ARG ...)
(function (delay ARG) ...)])))]
))
;; Attempt Two, fails with:
;; compile: bad syntax; reference to top-level identifiers is not
allowed, because no #%top syntax transformer is bound in: function1
(define-syntax define-lazy/2
(lambda (stx)
(syntax-case stx ()
[(define-lazy (OP ARG ...) BODY ...)
(with-syntax ((function (generate-temporaries '(function))))
#`(begin
(define (function ARG ...)
(let-syntax
((ARG (syntax-id-rules ()
[(_ RANDS (... ...))
((force ARG) RANDS (... ...))]
[_
(force ARG)]))
...)
BODY ...))
(define-syntax OP
(syntax-rules ()
[(OP ARG ...)
(function (delay ARG) ...)]))))]
)))
;; Attempt Three, fails with:
;; compile: bad syntax; reference to top-level identifiers is not
allowed, because no #%top syntax transformer is bound in: function1
(define-syntax define-lazy/3
(lambda (stx)
(syntax-case stx ()
[(define-lazy (OP ARG ...) BODY ...)
(datum->syntax-object
#'OP
(let ((function (car (generate-temporaries '(function)))))
`(begin
(define ,(cons function (syntax-e #'(ARG ...)))
,(cons
'let-syntax
(cons (map (lambda (arg-stx)
`(,arg-stx
(syntax-id-rules ()
[(_ RANDS (... ...))
((force ,arg-stx) RANDS (... ...))]
[_
(force ,arg-stx)])))
(syntax-e #'(ARG ...)))
(syntax-e #'(BODY ...)))))
(define-syntax ,#'OP
(syntax-rules ()
[(,#'OP ,@(syntax-e #'(ARG ...)))
(,function ,@(map (lambda (arg-stx)
`(delay ,arg-stx))
(syntax-e #'(ARG ...))))])))))]
)))
)
----
"There she is officers: the woman
who programmed me for evil!" -Bender