Вы не можете сделать это. Проблема в том, что вы генерируете символы с правильными именами, но вы просто возвращаете символы как есть, что означает, что with-syntax
дает им некоторый лексический контекст по умолчанию (и неправильный). Вместо этого вы должны использовать datum->syntax
и дать ему правильный контекст.
Ниже приведена версия вашего кода, которая работает так, как вы ожидаете. Чтобы узнать больше об этом, см. Мой недавний пост в блоге на тему негигиенических макросов.
Однако это не надежное решение. Что происходит, когда сеттеры и геттеры имеют разные имена? Более надежным решением было бы использовать имя структуры и извлечь из него нужную информацию (во время синтаксиса, в макросе) - подробности см. В руководстве . Также полезно задавать вопросы об этом в списке рассылки , так как может быть лучший способ получить то, что вы хотите, или лучшее решение, если вы ищете какую-то функцию, подобную точечной нотации.
#lang racket/load
(module util racket
(define-syntax increment!
(lambda (stx)
(syntax-case stx ()
[(increment! s sn fn i)
(let ([id (lambda (fmt)
(let ([str (format fmt (syntax-e #'sn) (syntax-e #'fn))])
(datum->syntax #'sn (string->symbol str))))])
(with-syntax ([set! (id "set-~a-~a!")]
[get (id "~a-~a")])
#'(set! s (+ i (get s)))))]
;; default increment of 1
[(increment! s sn fn) #'(increment! s sn fn 1)])))
(provide increment!))
(module bank racket
(require 'util)
(struct money (dollars pounds euros) #:mutable #:transparent)
(let ([m (money 0 50 20)])
(increment! m money pounds 100)
(increment! m money dollars)
m))
(require 'bank)