[plt-scheme] can macros introduce references to unit-imported ids?

From: Felix Klock's PLT scheme proxy (pltscheme at pnkfx.org)
Date: Mon Aug 11 16:35:53 EDT 2003

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...


(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
                         (syntax-object->datum #'NAME))))))
            #,(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)

(define bug-com@
   (unit/sig (make-variable)
     (import )
     (define make-variable
       (lambda l (cons 'MADE-VARIABLE l)))))

(define bug@
     (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@)

Posted on the users mailing list.