# Is there any equivalent way to emulate symbol-macrolet of ANSI Common Lisp with the Racket's Syntax?

**URL:** https://racket.discourse.group/t/is-there-any-equivalent-way-to-emulate-symbol-macrolet-of-ansi-common-lisp-with-the-rackets-syntax/2966
**Category:** Questions & Answers
**Created:** [June 15, 2024, 8:42am UTC](https://racket.discourse.group/t/is-there-any-equivalent-way-to-emulate-symbol-macrolet-of-ansi-common-lisp-with-the-rackets-syntax/2966 "2024-06-15T08:42:43Z")
**Posts on this page:** 14
**Page:** 1

<div class="post-metadata">

### Author: ![cametan](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/cametan/32/190_2.png) [@cametan](https://racket.discourse.group/u/cametan)
#### Post date: [June 15, 2024, 8:42am UTC](https://racket.discourse.group/t/is-there-any-equivalent-way-to-emulate-symbol-macrolet-of-ansi-common-lisp-with-the-rackets-syntax/2966/1 "2024-06-15T08:42:43Z")

</div>

Hello.

As the title says, is there any equivalent way to emulate symbol-macrolet of ANSI Common Lisp with the Racket's Syntax?

Thanks.

---

<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: [June 15, 2024, 11:46am UTC](https://racket.discourse.group/t/is-there-any-equivalent-way-to-emulate-symbol-macrolet-of-ansi-common-lisp-with-the-rackets-syntax/2966/2 "2024-06-15T11:46:09Z")

</div>

I have never really used Common Lisp, but, from a quick reading of the [HyperSpec](https://www.lispworks.com/documentation/lw51/CLHS/Body/s_symbol.htm), here is an implementation:

```scheme
#lang racket
;; SPDX-License-Identifier: CC0-1.0

(require (for-syntax syntax/parse
                     syntax/transformer)
         rackunit
         syntax/macro-testing)

(define-for-syntax (mutable-variable-transformer stx)
  (make-variable-like-transformer
   stx
   (syntax-parser
     #:track-literals
     #:literals [set!]
     [(set! _ rhs)
      #`(set! #,stx rhs)])))

(define-syntax (symbol-macrolet stx)
  (define-syntax-class bindings
    #:description "sequence of distinct binding pairs"
    (pattern ((~describe "binding pair"
                         [symbol:id expansion])
              ...)
      #:fail-when (check-duplicate-identifier
                   (syntax->list #'(symbol ...)))
                  "duplicate symbol macro name"))
  (syntax-parse stx
    [(_ :bindings body ...+)
     #'(let-syntax ([symbol (mutable-variable-transformer
                             #'expansion)]
                    ...)
         body ...)]))

(check-equal?
 (symbol-macrolet ([x 'foo])
   (list x (let ([x 'bar]) x)))
 '(foo bar))

(check-equal?
 (symbol-macrolet ([x '(foo x)])
   (list x))
 '((foo x))) ; hyperspec says ((FOO x))

(check-equal?
 (let ([bx (box 1)])
   (define-syntax implicit-bx
     (make-variable-like-transformer
      #'(unbox bx)
      #'(λ (v) (set-box! bx v))))
   (symbol-macrolet ([x implicit-bx])
     (list x (begin (set! x 2) x))))
 '(1 2))

(check-exn
 (match-lambda
   [(exn:fail:syntax "set!: not an identifier"
                     _
                     (list (app syntax->datum '(quote foo))))
    #t]
   [_
    #f])
 (λ ()
   (convert-syntax-error
    (symbol-macrolet ([x 'foo])
      (set! x 2)))))

```

The last two examples show my attempt to translate the specification that, "when the _`forms`_ of the [**`symbol-macrolet`**](https://www.lispworks.com/documentation/lw51/CLHS/Body/s_symbol.htm#symbol-macrolet) form are expanded, any use of [**`setq`**](https://www.lispworks.com/documentation/lw51/CLHS/Body/s_setq.htm#setq) to set the value of one of the specified variables is treated as if it were a [**`setf`**](https://www.lispworks.com/documentation/lw51/CLHS/Body/m_setf_.htm#setf)." However, as the final example illustrates, since Racket doesn't really have Common Lisp's notion of a [place](https://www.lispworks.com/documentation/lw51/CLHS/Body/05_aa.htm), for an `expansion` that isn't just an identifier, this will fail with a syntax error, and the message will include the `expansion`, not the source form. A less pedantic but more useful implementation might replace `mutable-variable-transformer` with just `make-variable-like-transformer` (i.e. without the optional second argument), which would raise a better syntax error, e.g. (for the last example) `set!: cannot mutate identifier at: x in: (set! x 2)`. Of course, you could also implement a variant of `set!` that supports something like Common Lisp's places or use an existing one, like [`srfi/17`](https://docs.racket-lang.org/srfi/srfi-17.html).

You might also be interested in [assignment transformers](https://docs.racket-lang.org/reference/syntax-model.html#%28tech._assignment._transformer%29) created by [`make-set!-transformer`](https://docs.racket-lang.org/reference/stxtrans.html#%28def._%28%28quote._~23~25kernel%29._make-set%21-transformer%29%29) or [`prop:set!-transformer`](https://docs.racket-lang.org/reference/stxtrans.html#%28def._%28%28quote._~23~25kernel%29._prop~3aset%21-transformer%29%29), the lower-level mechanism used to implement `make-variable-like-transformer`.

---

<div class="post-metadata">

### Author: ![cametan](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/cametan/32/190_2.png) [@cametan](https://racket.discourse.group/u/cametan)
#### Post date: [June 15, 2024, 2:16pm UTC](https://racket.discourse.group/t/is-there-any-equivalent-way-to-emulate-symbol-macrolet-of-ansi-common-lisp-with-the-rackets-syntax/2966/3 "2024-06-15T14:16:53Z")

</div>

Hello.

Phew! It works! Great! Black Magic!  
May God bless you.

At first, I assumed that somethings listed, though I am not familiar with, under syntax-case in the Scheme Programming Language 4th Edition might work, but I could not find the way to bind a symbol itself with a certain syntax expansion.  
I would read and study make-variable-like-transformer, syntax-parser, and syntax-parse, which are not included in the book, in Racket's document.

Anyway, thank you very much. You shined a light over my road ahead.

---

<div class="post-metadata">

### Author: ![sorawee](https://avatars.discourse-cdn.com/v4/letter/s/ea5d25/32.png) [@sorawee](https://racket.discourse.group/u/sorawee)
#### Post date: [June 15, 2024, 2:49pm UTC](https://racket.discourse.group/t/is-there-any-equivalent-way-to-emulate-symbol-macrolet-of-ansi-common-lisp-with-the-rackets-syntax/2966/4 "2024-06-15T14:49:13Z")

</div>

Slight nit: you might want to use

```scheme
(mutable-variable-transformer (quote-syntax expansion))

```

rather than

```scheme
(mutable-variable-transformer #'expansion)

```

Since the former will support

```scheme
(symbol-macrolet ((x ...))
   (let ([x 1]) x))

```

while the latter fails.

But yeah, I don’t know what @cametan is actually looking for. Is it `let-syntax`? Or is it `make-variable-like-transformer`? One can be used without the other.

---

<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: [June 15, 2024, 4:54pm UTC](https://racket.discourse.group/t/is-there-any-equivalent-way-to-emulate-symbol-macrolet-of-ansi-common-lisp-with-the-rackets-syntax/2966/5 "2024-06-15T16:54:51Z")

</div>

> [@cametan](#):
>
> At first, I assumed that somethings listed, thought I am not familiar with, under syntax-case in the Scheme Programming Language 4th Edition might work, but I could not find the way to bind a symbol itself with a certain syntax expansion.

For R6RS, these are called [identifier macros](https://www.r6rs.org/final/html/r6rs-lib/r6rs-lib-Z-H-13.html#node_idx_1136), and support for `set!` uses [`identifier-syntax`](https://www.r6rs.org/final/html/r6rs/r6rs-Z-H-14.html#node_idx_796) or [`make-variable-transformer`](https://www.r6rs.org/final/html/r6rs-lib/r6rs-lib-Z-H-13.html#node_idx_1120), which is almost identical to Racket's `make-set!-transformer`. These are discussed in [chapter 8 of TSPL4](https://scheme.com/tspl4/syntax.html#./syntax:s42).

Here is an example:

```scheme
#!/usr/bin/env scheme-script
;; appease Guile: !#
#!r6rs
;; SPDX-License-Identifier: CC0-1.0
(import (rnrs))

(define-syntax symbol-macrolet
  (syntax-rules ()
    [(_ ([symbol expansion] ...) body0 body ...)
     (let-syntax
         ([symbol (let ([exp #'((... ...) expansion)])
                    (make-variable-transformer
                     (lambda (stx)
                       (syntax-case stx (set!)
                         [(set! who rhs)
                          (if (identifier? exp)
                              #`(set! #,exp rhs)
                              (syntax-violation (syntax->datum #'who)
                                                "cannot mutate identifier"
                                                stx
                                                #'who))]
                         [(_ arg (... ...))
                          #`(#,exp arg (... ...))]
                         [id
                          (identifier? #'id)
                          exp]))))]
          ...)
       body0 body ...)]))

(define-syntax check-equal?
  (syntax-rules ()
    [(_ actual-expr expected-expr)
     (let ([src 'actual-expr]
           [actual actual-expr]
           [expected expected-expr])
       (unless (equal? actual expected)
         (display "!! Error: " (current-error-port)) (write src (current-error-port))
         (display "\nExpected: " (current-error-port)) (write expected (current-error-port))
         (display "\nActual: " (current-error-port)) (write actual (current-error-port))
         (newline)))]))

;; Syntax violation:
#;(symbol-macrolet ([x 'foo])
    (set! x 2))

(check-equal?
 (symbol-macrolet ([x 'foo])
   (list x (let ([x 'bar]) x)))
 '(foo bar))

(check-equal?
 (symbol-macrolet ([x '(foo x)])
   (list x))
 '((foo x))) ; hyperspec says ((FOO x))

(check-equal?
 (let ([bx (vector 1)])
   (define-syntax implicit-bx
     (make-variable-transformer
      (lambda (stx)
        (syntax-case stx (set!)
          [(set! _ rhs)
           #'(vector-set! bx 0 rhs)]
          [(_ arg ...)
           #'((vector-ref bx 0) arg ...)]
          [_
           #'(vector-ref bx 0)]))))
   (symbol-macrolet ([x implicit-bx])
     (list x (begin (set! x 2) x))))
 '(1 2))

(check-equal?
 (symbol-macrolet ((x ...))
   (let ([x 1]) x))
 1)

;; Written for https://racket.discourse.group/t/2966

```

> [@sorawee](#):
>
> Slight nit: you might want to use
> 
> ```scheme
> (mutable-variable-transformer (quote-syntax expansion))
> 
> ```
> 
> … [to] support
> 
> ```scheme
> (symbol-macrolet ((x ...))
> (let ([x 1]) x))
> 
> ```

Good catch, and the example helped! (You'll see that I worked around this specific issue in the R6RS version through the `(... ...)` escape, but `quote-syntax` is The Right Thing in Racket.)

I had in fact thought about this and even looked up [the old mailing list post](https://groups.google.com/g/racket-users/c/HaSmcTN0SA4/m/1XYa-mL5AgAJ) by @ryanc that got me to really understand expanding to `quote` and `quote-syntax` and stop getting `?: literal data is not allowed; no #%datum syntax transformer is bound` errors. What threw me off was then over-thinking the fact that defining `syntax-rules` in terms of `syntax-case` uses `syntax`, not `quote-syntax`. For `syntax-rules`, though, what the user writes on the right-hand side really is (in @ryanc's terms) a Syntax-Template, and template features like `...` and pattern variables are supposed to have their Syntax-Template meaning, even though the Syntax-Template context comes from being a subform of `syntax-rules`, rather than of `syntax`, `quasisyntax`, `syntax/loc`, etc. In contrast, a right-hand side of `symbol-macrolet` (at least AIUC) is a literal fragments of program, and thus needs to expand to, in @ryanc's words, "an Expression that produces the same _syntax object_ at run time", where "run time" in this case is the generated macro's compile time.

---

<div class="post-metadata">

### Author: ![cametan](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/cametan/32/190_2.png) [@cametan](https://racket.discourse.group/u/cametan)
#### Post date: [June 15, 2024, 6:07pm UTC](https://racket.discourse.group/t/is-there-any-equivalent-way-to-emulate-symbol-macrolet-of-ansi-common-lisp-with-the-rackets-syntax/2966/6 "2024-06-15T18:07:03Z")

</div>

Hello.

> [@sorawee](#):
>
> But yeah, I don’t know what @cametan is actually looking for. Is it `let-syntax`? Or is it `make-variable-like-transformer`? One can be used without the other.

Here is the situation and this is a sort of experiment.  
I started to re-read On Lisp, which a Lisp hacker, Paul Graham wrote.  
He there showed a macro named `on-cdrs`, which abstracts a cdr-recursive function.

```scheme
(defun lrec (rec & optional base)
  (labels ((self (lst)
             (if (null lst)
                 (if (functionp base)
                     (funcall base)
                     base)
                 (funcall rec (car lst)
                          #'(lambda ()
                              (self (cdr lst)))))))
    #'self))

(defmacro alrec (rec &optional base)
  (let ((gfn (gensym)))
    `(lrec #'(lambda (it ,gfn)
               (symbol-macrolet ((rec (funcall ,gfn)))
                 ,rec))
           ,base)))

(defmacro on-cdrs (rec base &rest lsts)
  `(funcall (alrec ,rec #'(lambda () ,base)) ,@lsts))

```

However, technically speaking, you would notice the macro, `on-cdrs`, is basically `foldr` wrapped with the syntax-case of Racket:

```scheme
(define-syntax (on-cdrs x)
  (syntax-case x ()
    ((on-cdrs expr base lst ...)
     (with-syntax ((it (datum->syntax #'on-cdrs 'it))
                   (rec (datum->syntax #'on-cdrs 'rec)))
       #'(foldr (lambda (it rec)
                  expr) base lst ...)))))

```

Otherwise, you can say this macro is `foldr` using anaphora(`it` and `rec`), instead of using a lambda expression.  
In most cases, this macro is O.K.; however Paul Graham gave this example.

```scheme
;; ANSI Common Lisp Version
(defun maxmin (args)
  (when args
    (on-cdrs (multiple-value-bind (mx mn) rec
               (values (max mx it) (min mn it)))
             (values (car args) (car args))
             (cdr args))))

;; Racket Version
(define (maxmin args)
  (unless (null? args)
    (on-cdrs (let-values (((mx mn) rec))
               (values (max mx it) (min mn it)))
             (values (car args) (car args))
             (cdr args))))

```

This does not properly work, because `foldr` is not planned to receive `values`.  
Of course, practically speaking, I believe that nobody likes to use `values` as above, because what a function returns is important, but internally, passing `values` does not seem a good idea; thus everyone may like to write the code like this:

```scheme
(define (maxmin args)
  (unless (null? args)
    (apply values
           (on-cdrs (match-let ((`(,mx ,mn) rec))
                      `(,(max mx it) ,(min mn it)))
                    `(,(car args) ,(car args))
                    (cdr args)))))

```

I think this should be the right code...but, isn't it frustrating? Is Racket lost? Do we have to re-implement `foldr`?  
Racket has `delay` and `force`, thus I believe we can have such a framework...:

```scheme
(define-syntax (on-cdrs x)
  (syntax-case x ()
    ((on-cdrs expr base lst ...)
     (with-syntax ((it (datum->syntax #'on-cdrs 'it))
                   (rec (datum->syntax #'on-cdrs 'rec)))
       #'(force
          (foldr (lambda (it gfn)
                  #| here, need something syntactically binding rec to (force gfn) |#
                  (delay expr)) (delay base) lst ...))))))

```

And here, I was stuck.  
As you implied, at first I thought using let-syntax is O.K., but embarrassing to admit, I misunderstood that `let-syntax` is something like `symbol-macrolet` of ANSI Common Lisp:

```scheme
 (define-syntax (on-cdrs x)
  (syntax-case x ()
    ((on-cdrs expr base lst ...)
     (with-syntax ((it (datum->syntax #'on-cdrs 'it))
                   (rec (datum->syntax #'on-cdrs 'rec)))
       #'(force
          (foldr (lambda (it gfn)
                  (let-syntax ((rec (syntax-rules ()
                                      ((_) (force gfn)))))
                    (delay expr))) (delay base) lst ...))))))

```

Yes, it works, but every time we use this version, the anaphora "`rec`" has to be sandwiched between a parenthesis and a sisehtnerap.

```scheme
(define (maxmin args)
  (unless (null? args)
    (on-cdrs (let-values (((mx mn) (rec))) ; rec always has to have a ( and a )
               (values (max mx it) (min mn it)))
             (values (car args) (car args))
             (cdr args))))

```

That is why I was looking for a technique to bind a symbol to something, directly expanding into an expression in the context, or a substitution for ANSI Common Lisp's `symbol-macrolet` in Racket.

Thanks.

---

<div class="post-metadata">

### Author: ![cametan](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/cametan/32/190_2.png) [@cametan](https://racket.discourse.group/u/cametan)
#### Post date: [June 15, 2024, 6:38pm UTC](https://racket.discourse.group/t/is-there-any-equivalent-way-to-emulate-symbol-macrolet-of-ansi-common-lisp-with-the-rackets-syntax/2966/7 "2024-06-15T18:38:01Z")

</div>

> [@LiberalArtist](#):
>
> For R6RS, these are called [identifier macros](https://www.r6rs.org/final/html/r6rs-lib/r6rs-lib-Z-H-13.html#node_idx_1136), and support for `set!` uses [`identifier-syntax`](https://www.r6rs.org/final/html/r6rs/r6rs-Z-H-14.html#node_idx_796) or [`make-variable-transformer`](https://www.r6rs.org/final/html/r6rs-lib/r6rs-lib-Z-H-13.html#node_idx_1120), which is almost identical to Racket's `make-set!-transformer`. These are discussed in [chapter 8 of TSPL4](https://scheme.com/tspl4/syntax.html#./syntax:s42).

O.K. I will check that out.  
Thank you.

---

<div class="post-metadata">

### Author: ![shawnw](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/shawnw/32/1031_2.png) [@shawnw](https://racket.discourse.group/u/shawnw)
#### Post date: [June 15, 2024, 7:38pm UTC](https://racket.discourse.group/t/is-there-any-equivalent-way-to-emulate-symbol-macrolet-of-ansi-common-lisp-with-the-rackets-syntax/2966/8 "2024-06-15T19:38:10Z")

</div>

My go at Racket implementations of these `alrec` and `on-cdrs` macros, using syntax parameters for the `it` and `rec` forms (Which is generally a better approach than injecting those symbols into the macro). These versions work with expressions that return multiple values as well as single-valued ones without needing the extra parens around `rec`.

```scheme
#lang racket/base

(require racket/contract racket/stxparam syntax/parse/define
         (for-syntax racket/base))

(define (lrec rec [base '()])
  (define (self lst)
    (if (null? lst)
        (if (procedure? base)
            (base)
            base)
        (rec (car lst) (lambda () (self (cdr lst))))))
  self)

(define-syntax-parameter it
  (lambda (stx) (raise-syntax-error #f "use of it outside anaphoric macro")))
(define-syntax-parameter rec
  (lambda (stx) (raise-syntax-error #f "use of rec outside alrec")))

(define-syntax-parse-rule (alrec e:expr (~optional base:expr))
  (lrec (lambda (x gfn)
          (syntax-parameterize ([it (make-rename-transformer #'x)]
                                [rec (lambda (stx) #'(gfn))])
            e))
        (~? base '())))

(define-syntax-parse-rule (on-cdrs e:expr base:expr lsts:expr ...)
     ((alrec e (lambda () base)) lsts ...))

;;; Example usages
(define (our-length lst)
  (on-cdrs (add1 rec) 0 lst))

(define/contract (maxmin args)
  (-> (non-empty-listof real?) (values real? real?))
  (on-cdrs (let-values ([(mx mn) rec])
             (values (max mx it) (min mn it)))
           (values (car args) (car args))
           (cdr args)))

(our-length '(1 2 3 4))
(maxmin '(1 2 5 3 4))

```

---

<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: [June 15, 2024, 8:59pm UTC](https://racket.discourse.group/t/is-there-any-equivalent-way-to-emulate-symbol-macrolet-of-ansi-common-lisp-with-the-rackets-syntax/2966/9 "2024-06-15T20:59:33Z")

</div>

> [@shawnw](#):
>
> using syntax parameters for the `it` and `rec` forms (Which is generally a better approach than injecting those symbols into the macro)

Yes, this is key!

> [@shawnw](#):
>
> ```scheme
> [rec (lambda (stx) #'(gfn))])
> 
> ```

Nit: You should use `(make-variable-like-transformer #'(gfn))` here so that this expression:

```scheme
((on-cdrs (rec it)
          (let loop ([x 0])
            (case-lambda
              [()
               x]
              [(y)
               (loop (+ x y))]))
          '(3 2 1 4)))

```

evaluates to `10`, not `0`.

> [@shawnw](#):
>
> ```scheme
> (define-syntax-parse-rule (on-cdrs e:expr base:expr lsts:expr ...)
> ((alrec e (lambda () base)) lsts ...))
> 
> ```

> [@cametan](#):
>
> ```scheme
> (defmacro on-cdrs (rec base &rest lsts)
> `(funcall (alrec ,rec #'(lambda () ,base)) ,@lsts))
> 
> ```

Complaint for Paul Graham (unless I badly misunderstand the Common Lisp semantics): `on-cdrs` is written to accept zero or more `lsts` expressions, but an `alrec` expression evaluates to a function that accepts exactly one list.

* * *

An idiomatic Racket way to write `maxmin` might be something like this:

```scheme
(define maxmin
  (match-lambda
    [(cons arg0 arg*)
     (for/fold ([mx arg0]
                [mn arg0])
               ([it (in-list arg*)])
       (values (max mx it)
               (min mn it)))]))

```

From a macro design perspective, a notable difference between `for/fold` and `on-cdrs` is that, while both allow working with an arbitrary number of values, `for/fold` makes the number of values in a _particular_ `for/fold` expression statically visible, whereas, with `on-cdrs`, the macro implementation has to handle expressions that produce an _unknown_ number of values. In Racket, knowing the number of values is preferable for style and efficiency. The considerations may way differently in Common Lisp, given e.g. the semantics for coercing multiple values returned to a single-value-expecting continuation.

---

<div class="post-metadata">

### Author: ![shawnw](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/shawnw/32/1031_2.png) [@shawnw](https://racket.discourse.group/u/shawnw)
#### Post date: [June 15, 2024, 11:51pm UTC](https://racket.discourse.group/t/is-there-any-equivalent-way-to-emulate-symbol-macrolet-of-ansi-common-lisp-with-the-rackets-syntax/2966/10 "2024-06-15T23:51:04Z")

</div>

> [@LiberalArtist](#):
>
> Nit: You should use `(make-variable-like-transformer #'(gfn))` here

I'll have to look into that one. Never heard of it before.

> [@](#):
>
> Complaint for Paul Graham (unless I badly misunderstand the Common Lisp semantics): `on-cdrs` is written to accept zero or more `lsts` expressions, but an `alrec` expression evaluates to a function that accepts exactly one list.

I didn't dig deeply enough into them to notice that oversight. Weird.

---

<div class="post-metadata">

### Author: ![cametan](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/cametan/32/190_2.png) [@cametan](https://racket.discourse.group/u/cametan)
#### Post date: [June 16, 2024, 5:01pm UTC](https://racket.discourse.group/t/is-there-any-equivalent-way-to-emulate-symbol-macrolet-of-ansi-common-lisp-with-the-rackets-syntax/2966/11 "2024-06-16T17:01:17Z")

</div>

Hello.

Hmm...My Racket(8.13) does not recognize `make-rename-transformer`, `require`-ing it though.  
Let me take a while to study around it.

Thanks.

---

<div class="post-metadata">

### Author: ![soegaard](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/soegaard/32/19_2.png) [@soegaard](https://racket.discourse.group/u/soegaard)
#### Post date: [June 16, 2024, 5:22pm UTC](https://racket.discourse.group/t/is-there-any-equivalent-way-to-emulate-symbol-macrolet-of-ansi-common-lisp-with-the-rackets-syntax/2966/12 "2024-06-16T17:22:41Z")

</div>

Maybe you need an `(require (for-syntax ...))` around it.

---

<div class="post-metadata">

### Author: ![cametan](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/cametan/32/190_2.png) [@cametan](https://racket.discourse.group/u/cametan)
#### Post date: [June 16, 2024, 6:24pm UTC](https://racket.discourse.group/t/is-there-any-equivalent-way-to-emulate-symbol-macrolet-of-ansi-common-lisp-with-the-rackets-syntax/2966/13 "2024-06-16T18:24:20Z")

</div>

Hello.

> [@soegaard](#):
>
> Maybe you need an `(require (for-syntax ...))` around it.

Yes, of course I did.  
I might make a mistake...  
Well, whatever, I need to study around it , taking a while.

Thanks.

---

<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: [June 16, 2024, 9:41pm UTC](https://racket.discourse.group/t/is-there-any-equivalent-way-to-emulate-symbol-macrolet-of-ansi-common-lisp-with-the-rackets-syntax/2966/14 "2024-06-16T21:41:34Z")

</div>

> [@shawnw](#):
>
> > [@LiberalArtist](#):
> >
> > Nit: You should use `(make-variable-like-transformer #'(gfn))` here
> 
> I'll have to look into that one. Never heard of it before.

It's equally possible to do this correctly "by hand" (the whole implementation is only 23 lines), but `make-variable-like-transformer` takes care of subtleties for robustness, like adding `#%expression`, that are easy to forget.

> <https://github.com/racket/racket/blob/a8d8f3c63cddb49ea6f61f9bf06dad4ef95e0908/racket/collects/syntax/transformer.rkt#L13-L35>
