# How to match up macro-generated and user-defined identifiers?

**URL:** <https://racket.discourse.group/t/how-to-match-up-macro-generated-and-user-defined-identifiers/2379>\
**Category:** Questions & Answers\
**Tags:** typed-racket, macro\
**Created:** [October 12, 2023, 7:50am UTC](https://racket.discourse.group/t/how-to-match-up-macro-generated-and-user-defined-identifiers/2379 "2023-10-12T07:50:57Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![pcn](https://avatars.discourse-cdn.com/v4/letter/p/65b543/32.png) [@pcn](https://racket.discourse.group/u/pcn)\
**Post date:** [October 12, 2023, 7:50am UTC](https://racket.discourse.group/t/how-to-match-up-macro-generated-and-user-defined-identifiers/2379/1 "2023-10-12T07:50:57Z")

</div>

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:

```scheme
(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:

```scheme
(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?

```scheme
(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.

```scheme
(define-implementation interp : (expr (Env → V))
  ...)

```

Many thanks!!

---

<div class="post-metadata">

**Author:** ![usao](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/usao/32/1375_2.png) [@usao](https://racket.discourse.group/u/usao)\
**Post date:** [October 12, 2023, 8:53am UTC](https://racket.discourse.group/t/how-to-match-up-macro-generated-and-user-defined-identifiers/2379/2 "2023-10-12T08:53:27Z")

</div>

I’m not sure what’s the “proper” way, but simply replacing (not stripping!) the contexts works:

```scheme
(define-syntax-parser define-signature
  [(_ (sig:id t:id ...) (~seq x:id (~literal :) tₓ:expr) ...)
   #:with define-impl (format-id #'sig
                                 "define-~a-implementation" #'sig)
   #'(begin
       (struct (t ...) sig ([x : tₓ] ...) #:transparent)
       (define-syntax-parser define-impl
         [(_ impl:id : (t* (... ...)) d (... ...))
          #:with (x* (... ...)) (replace-context #'impl #'(x ...))
          #:with (t** (... ...)) #'(t ...)
          #:with (tₓ* (... ...)) #'(tₓ ...)
          #'(define impl : (sig t* (... ...))
              (let ()
                (define-type t** t*) (... ...)
                (: x* : tₓ*) (... ...)
                d (... ...)
                (sig x* (... ...))))]))])

```

Edit: And to the second question, `define-syntax` bindings can be accessed through `syntax-local-value`. This is how macros work in the first place (they are just procedures bound this way, nothing special).

---

<div class="post-metadata">

**Author:** ![pcn](https://avatars.discourse-cdn.com/v4/letter/p/65b543/32.png) [@pcn](https://racket.discourse.group/u/pcn)\
**Post date:** [October 13, 2023, 4:11am UTC](https://racket.discourse.group/t/how-to-match-up-macro-generated-and-user-defined-identifiers/2379/3 "2023-10-13T04:11:19Z")

</div>

Thank you very much!!
