The question is likely very basic. I'm just rusty
I'm trying to implement poor man's module that can be parameterized by types, using structs. An example is I can do something like:
(define-signature (expr E)
ref : (Symbol β E)
app : (E E β E)
lam : (Symbol E β E))
(define-expr-implementation interp : ((Env β V))
(define ((ref x) Ο) (Ο x))
(define ((app eβ eβ) Ο) ((eβ Ο) (eβ Ο)))
(define ((lam x e) Ο) (Ξ» (v) (e (ext Ο x v)))))
(define-expr-implementation stage : ((Syntaxof Any))
...)
And have generated code like below:
(struct (E) expr ([ref : (Symbol β E)]
[app : (E E β E)]
[lam : (Symbol E β E)]))
(define interp : (expr (Env β V))
(let ()
(define-type E (Env β V))
(: ref : (Symbol β E))
(: app : (E E β E))
(: lam : (Symbol E β E))
(define ((ref x) Ο) (Ο x))
(define ((app eβ eβ) Ο) ((assert (eβ Ο) procedure?) (eβ Ο)))
(define ((lam x e) Ο) (Ξ» ((v : V)) (e (ext Ο x v))))
(expr ref app lam)))
(define stage : (expr (Syntaxof Any))
(let ()
(define-type E (Syntaxof Any))
(: ref : (Symbol β E))
(: app : (E E β E))
(: lam : (Symbol E β E))
...
(expr ref app lam)))
My current macro looks like below, and the problem I'm having is the bindings in the macro-generated type annotations don't match the bindings in the user-provided implementation. I tried stripping their context with (format-id #f ...)
and (datum->syntax #f (syntax->datum ...))
, but that didn't work. What's the easiest way I can make the bindings match up?
(define-syntax-parser define-signature
[(_ (sig:id t:id ...) (~seq (~seq x:id (~literal :) tβ:expr) ...))
(with-syntax ([define-impl (format-id #'sig "define-~a-implementation" (syntax->datum #'sig))])
#`(begin
(struct (t ...) sig ([x : tβ] ...) #:transparent)
(define-syntax-parser define-impl
[(_ impl:id : (t* (... ...)) d (... ...))
(with-syntax ([(x* (... ...)) (map (Ξ» (z) (format-id #f "~a" z)) '(x ...))]
[(t** (... ...)) '(t ...)]
[(tβ* (... ...)) '(tβ ...)]
[(d (... ...))
(datum->syntax #f (syntax->datum #'(d (... ...))))])
(define stx
#'(define impl : (sig t* (... ...))
(let ()
(define-type t** t*) (... ...)
(: x* : tβ*) (... ...)
d (... ...)
(sig x* (... ...)))))
(printf "Generated:~n")
(pretty-print (syntax->datum stx))
stx)])))])
;; Error from generated code:
; Type Checker: Declaration for `ref' provided, but `ref' has no definition
; in: ref
An unrelated question: I'm making define-signature
generate a macro for each signature just because I don't know how to remember the struct information across different macros. If I want to do something like below, where define-implementation
knows about the field names and types of expr
, how do I do that? I tried (syntax-property expr ...)
but that didn't work, and (define-for-syntax info ...)
wasn't going to retain the state across different expansions.
(define-implementation interp : (expr (Env β V))
...)
Many thanks!!