[plt-scheme] can macros introduce references to unit-imported ids?
PLT experts-
I suspect that the answer to my question is "The unit/sig macro is
broken", as Matthew explained in his email from May 26th, 2003 with the
subject line "macros for unit/sig"
However, since I'm not certain that the explanation he gave there
applies here, and because I don't see an analogous work-around here to
the one that Matthew gave in the above referenced email (note that I'm
already trying to use datum->syntax-object to force the reference into
the proper lexical context), I figured it was best to ask the mailing
list about the behavior below.
I have a macro, DEFINE-VARIABLE, which generates an expression that
references a procedure, MAKE-VARIABLE. Due to mutually recursive
references in the Erwin source files, I needed to define make-variable
within a unit, which for this email we'll call bugc at . So uses of
define-variable are meant to occur within units that import the bugc^
signature. (I would personally prefer a setup where the dependency of
define-variable on bugc^ were satisfied implicitly within the language
module that defines the define-variable syntax, but lets ignore that
stylistic problem that might be impossible to solve, and focus on the
technical one at hand...)
Based on my own investigations using expand, expand-once, etc, it seems
like the define-variable expansions are ending up with the
make-variable identifier being tagged as a free/top-level binding, not
a lexical one. [[I don't understand the interaction between units and
macros well enough to say whether this is correct behavior or > not]].
This leads to the macro expanding into an expression that, when
executed, has an improper binding for make-variable.
I reduced the bug down to the following test case... the reduction was
rather ad hoc, so I'm actually not certain that fixing the below would
fix my bug, but since the error message is the same [[the error seems
to be that I'm able to break the unit abstraction and get at the
undefined value initially given to unit imported bindings]], then I'd
like to see what diagnosis people offer...
-Felix
(require (lib "unitsig.ss"))
(define-signature bug1^ (boo-var))
(define-signature bugc^ (make-variable))
(define-syntax (define-variable stx)
(syntax-case stx ()
[(define-variable NAME DESC VALUE TEST)
(let ((gen-name (string->symbol
(string-append
"edwin-variable$"
(symbol->string
(syntax-object->datum #'NAME))))))
#`(define
#,(datum->syntax-object #'NAME gen-name)
(#,(datum->syntax-object #'NAME 'make-variable)
(quote NAME) DESC VALUE #f TEST)))]))
(define bug1@
(unit/sig bug1^
(import bugc^)
(define boo-var
(let ()
;; Loading proceeds without error (and with some output) if
;; below line is uncommented
;; (define make-variable (lambda l (printf "make-variable was
called~n") #f))
(define-variable bug1-var "bug1-var desc" (list 'b1v) #f)
edwin-variable$bug1-var))))
(define bug-com@
(unit/sig (make-variable)
(import )
(define make-variable
(lambda l (cons 'MADE-VARIABLE l)))))
(define bug@
(compound-unit/sig
(import)
(link (B1 : bug1^ (bug1@ BC))
(BC : bugc^ (bug-com@)))
(export (open B1))))
;; Unless you comment out this invocation
;; (or uncomment the make-variable definition within bug1@),
;; attempts to run this program produce the error:
#|
procedure application: expected procedure, given: #<undefined>;
arguments were: bug1-var "bug1-var desc" (b1v) #f #f
|#
(define-values/invoke-unit/sig bug1^ bug@)