# Make-variable-like-transformer

**URL:** <https://racket.discourse.group/t/make-variable-like-transformer/4323>\
**Category:** Questions & Answers\
**Tags:** question\
**Created:** [July 20, 2026, 11:04am UTC](https://racket.discourse.group/t/make-variable-like-transformer/4323 "2026-07-20T11:04:54Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![joskoot](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/joskoot/32/1964_2.png) [@joskoot](https://racket.discourse.group/u/joskoot)\
**Post date:** [July 20, 2026, 11:04am UTC](https://racket.discourse.group/t/make-variable-like-transformer/4323/1 "2026-07-20T11:04:54Z")

</div>

Why does the following give an error?

state-a: undefined;  
cannot reference an identifier before its definition  
in module: 'anonymous-module

Wrong use of datum-\>syntax?  
How to fix this?

```scheme
#lang racket

(require (for-syntax (only-in syntax/transformer make-variable-like-transformer)))

(struct state (a) #:mutable #:constructor-name make-state #:omit-define-syntaxes)
(define state (make-state 1))

(define-syntax (state-component stx)
  (syntax-case stx ()
    ((_ id)
     (with-syntax
       ((state-id
          (datum->syntax stx
           (string->symbol (format "state-~s" (syntax-e #'id)))))
        (set-state-id!
          (datum->syntax stx
           (string->symbol (format "set-state-~s!" (syntax-e #'id))))))
       #'(define-syntax id
           (make-variable-like-transformer
             (state-id state)
             (λ (v) (set-state-id! state v))))))))

(state-component a)

```

---

<div class="post-metadata">

**Author:** ![LiberalArtist](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/liberalartist/32/151_2.png) [@LiberalArtist](https://racket.discourse.group/u/LiberalArtist)\
**Post date:** [July 20, 2026, 2:01pm UTC](https://racket.discourse.group/t/make-variable-like-transformer/4323/2 "2026-07-20T14:01:22Z")

</div>

I think the problem is easier to see if we replace `(state-component a)` with its expansion, as reported by the macro stepper:

```scheme
#lang racket

(require (for-syntax (only-in syntax/transformer
                              make-variable-like-transformer)))

(struct state (a)
  #:mutable
  #:constructor-name make-state
  #:omit-define-syntaxes)
(define state (make-state 1))

(define-syntax a
  (make-variable-like-transformer
   (state-a state)
   (λ (v)
     (set-state-a! state v))))

```

This is trying to use `state`, `state-a`, and `set-state-a!` at compile time, but those values don’t exist until runtime. You need to pass `make-variable-like-transformer` a syntax-quoted `#'(state-a state)`\[1\] that it should expand to, not the value of the expression `(state-a state)`.

Here is a working version, with only two other changes I couldn’t resist: generating names is much better with `format-id`, and using the scope from `#'id` rather than `stx` is more robust if some other macro might expand to `state-component`:

```scheme
#lang racket

(require (for-syntax (only-in racket/syntax
                              format-id)
                     (only-in syntax/transformer
                              make-variable-like-transformer)))

(module+ test
  (require rackunit)
  (check-eqv? a 1)
  (set! a 5)
  (check-eqv? a 5))

(struct state (a)
  #:mutable
  #:constructor-name make-state
  #:omit-define-syntaxes)
(define state (make-state 1))

(define-syntax (state-component stx)
  (syntax-case stx ()
    [(_ id)
     (with-syntax
         ([state-id (format-id #'id "state-~a" #'id)]
          [set-state-id! (format-id #'id "set-state-~a!" #'id)])
       #`(define-syntax id
           (make-variable-like-transformer
            #'(state-id state)
            #'(λ (v)
                (set-state-id! state v)))))]))

(state-component a)

```

* * *

Looking beyond the immediate problem, I’d guess that you have written `define-state-component` because, in reality, you have several components. I am allergic to writing out lists of fields multiple times—in the `struct` declaration, in the arguments to `make-state`, and in the uses of `define-state-component`—and I’d be sad that DrRacket’s scope-aware renaming couldn’t handle `a`. I would be inclined to do something like this:

```scheme
#lang racket

(require (for-syntax racket/syntax
                     syntax/transformer)
         syntax/parse/define)

(module+ test
  (require rackunit)
  (check-eqv? a 1)
  (set! a 5)
  (check-eqv? a 5)
  (check-equal? b '(a b c))
  (set! b 'done)
  (check-eq? b 'done))

(define-syntax-parse-rule (define-state name:id
                            (~seq field:id init-val:expr) ...)
  #:with make-name (format-id #'name "make-~a" #'name #:subs? #t)
  #:with ((~seq field-ref set-field!) ...)
  (for*/list ([fld (in-list (attribute field))]
              [fmt `("~a-~a" "set-~a-~a!")])
    (format-id fld fmt #'name fld))
  (begin
    (struct name (field ...)
      #:mutable
      #:constructor-name make-name
      #:omit-define-syntaxes)
    (define name
      (make-name init-val ...))
    (define-syntax field
      (make-variable-like-transformer
       (quote-syntax (field-ref name))
       (quote-syntax (λ (v)
                       (set-field! name v)))))
    ...))

(define-state state
  a 1
  b '(a b c))

```

In real life, I [did something like this](https://github.com/racket/web-server/blob/080d2ea7dfc8b8e9a147f2d3155970098eac69b0/web-server-lib/web-server/safety-limits.rkt#L29) to define the web server’s [“safety limits”](https://docs.racket-lang.org/web-server-internal/dispatch-server-unit.html#%28part._safety-limits%29) construct with `make-safety-limits` and `make-unlimited-safety-limits`.

Often, when we talk about why macros are so useful, we give examples of using macros to implement new linguistic constructs. But I think the macro that is used exactly once is an underappreciated genre!

* * *

1. More correctly, `(quote-syntax (state-a state))`, but we can ignore that in this case.

---

<div class="post-metadata">

**Author:** ![joskoot](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/joskoot/32/1964_2.png) [@joskoot](https://racket.discourse.group/u/joskoot)\
**Post date:** [July 20, 2026, 3:09pm UTC](https://racket.discourse.group/t/make-variable-like-transformer/4323/3 "2026-07-20T15:09:59Z")

</div>

Thanks for your rapìd reply. It works (of course) Including the definition of the struct in the macro such as to avoid repeated lists of field-names, is a good idea, Makes adding or removing fields in new versions easier and less work.  
Jos Koot
