[plt-scheme] macros for unit/sig
I'm learning a few things at once here, so please forgive any
muddle-headedness... I'm having some trouble defining macros that
generate unit/sig. Below is an example: a signature called "algorithm"
that imports a math unit to compute something. I want to introduce a
"define-algorithm" form that hides the plumbing.
I managed to figure out (admittedly without quite understanding it) how
to match the implementation's function with the function in the
signature -- by introducing it to syntax-case as a keyword -- but now
the problem is that an implementation can't use any of the imported
identifiers. The following code produces a "reference to undefined
identifier: plus".
At what point is the body being evaluated? I would've expected it not
to evaluate it until after it expanded the macro, so the reference
would safely be within the body of the unit/sig declaration. Or is this
a case where hygiene is causing identifiers not to match?
Thanks so much,
Dave
;; --
(require (lib "unitsig.ss"))
(define-signature math^ (plus minus times divide))
(define math@
(unit/sig math^
(import)
(define plus +)
(define minus -)
(define times *)
(define divide /)))
(define-signature algorithm^ (compute))
(define-syntax (define-algorithm expr)
(syntax-case expr (define compute)
[(_ name d1 d2 ...)
(with-syntax
([defs
(let f ([ds (syntax->list (syntax (d1 d2 ...)))])
(with-syntax
([first
(syntax-case (car ds) (define compute)
[(define (compute) e1 e2 ...)
(syntax (define compute (lambda () e1 e2 ...)))]
[(define (compute a1 a2 ...) e1 e2 ...)
(syntax (define compute (lambda (a1 a2 ...) e1 e2
...)))]
[(define compute e)
(syntax (define compute e))]
[(define (fn) e1 e2 ...)
(syntax (define fn (lambda () e1 e2 ...)))]
[(define (fn a1 a2 ...) e1 e2 ...)
(syntax (define fn (lambda (a1 a2 ...) e1 e2
...)))]
[(define x e)
(syntax (define x e))])])
(if (null? (cdr ds))
(syntax first)
(with-syntax ([rest (f (cdr ds))])
(syntax (begin first rest))))))])
(syntax (define name
(unit/sig algorithm^
(import math^)
defs))))]))
(define-algorithm alg@
(define (compute) (plus (times 2 3) 4)))
(define linked@
(compound-unit/sig
(import)
(link (MATH : math^ (math@))
(ALG : algorithm^ (alg@ MATH)))
(export (open ALG))))
(define-values/invoke-unit/sig algorithm^ linked@)
(compute) ; error: reference to undefined identifier: plus
;; --