Macros 从球拍宏中取消报价

Macros 从球拍宏中取消报价,macros,racket,quote,Macros,Racket,Quote,我有一个函数,它对表达式进行一些处理: (struct sym (s) #:transparent) (define (foo-fn ex) (match ex [(? symbol? s) `(sym (quote ,s))] [(? list? xs) (cons (car xs) (map foo-fn (cdr xs)))] [x x])) 此功能按预期工作: > (foo-fn '(cons x y)) '(cons (sym 'x) (sym '

我有一个函数,它对表达式进行一些处理:

(struct sym (s) #:transparent)

(define (foo-fn ex)
  (match ex
    [(? symbol? s) `(sym (quote ,s))]
    [(? list? xs) (cons (car xs) (map foo-fn (cdr xs)))]
    [x x]))
此功能按预期工作:

> (foo-fn '(cons x y))
'(cons (sym 'x) (sym 'y))
现在,我尝试创建一个宏,它接受给定的表达式,并用
foo-fn
的结果替换它。我已经设法找到了一些方法

(define-syntax-rule (foo ex)
  (foo-fn (quote ex)))
但是,这个宏仍然给出了引用的表达式,我希望表达式本身。也就是说,我当前的代码给出

> (foo (cons x y))
'(cons (sym 'x) (sym 'y))
我希望结果是

> (foo (cons x y))
(cons (sym 'x) (sym 'y))
> (foo (cons x y))
(cons (sym 'x) (sym 'y))
我已经设法通过使用
eval
找到了一个解决方法,但我很确定这不是宏的使用方式(如果我错了,请纠正我)


虽然上述方法有效,但我认为使用宏是不正确的。首选的方法是什么?

这里的根本问题不在您的
foo
宏中,而是在
foo fn
中。
foo-fn
操作基准,而不是语法对象,因此它丢弃了所有词汇上下文和源位置信息。这是一个不可逆的操作,因此无法从引用的表达式“返回”到语法片段

与使用
foo-fn
执行源代码转换不同,您可能希望
foo
宏本身执行语法解析。使用,这非常简单:

(require syntax/parse/define)

(struct sym (s) #:transparent)

(define-syntax-parser foo
  [(_ s:id) #'(sym 's)]
  [(_ (f x ...)) #'(f (foo x) ...)]
  [(_ x) #'x])
通过将其实现为宏,可以实现语法到语法的转换,而不是数据到数据的转换,这可以正确地保留词汇上下文。(这种保存是“宏观卫生”概念的组成部分。)

现在,您可以使用
foo
宏获得预期的结果:

> (foo (cons x y))
(cons (sym 'x) (sym 'y))