我有以下代码组成传统的宏eat
,它使用引号('(eating food)
)和make-rename-transformer
宏,该宏应该将lunch
转换为{ {1}}。完整的代码是:
sandwich
由于#lang racket
(require (for-syntax syntax/parse))
(define-syntax lunch (make-rename-transformer #'sandwich))
(define-syntax (eat stx)
(syntax-parse stx
[(_ food)
#''(eating food)]))
(eat lunch)
只是lunch
的重命名变换器,我希望它会评估为sandwich
,因此(eat sandwich)
,但是当我运行它时,我会得到它:
'(eating sandwich)
这不是我的预期。有没有什么办法可以修改它,以便重命名引号转换? (好像我使用了'(eating lunch)
函数而不是list
。)
答案 0 :(得分:0)
这里的问题只是一个扩展的顺序。与函数不同,无论如何,从内到外评估。宏本质上扩展到外面,这是像Racket这样的语言宏观扩展的内在属性。
所以,问题在于宏expa的第一步
#lang racket
(define-syntax lunch (make-rename-transformer #'sandwich))
'(eating lunch)
此时lunch
不再是标识符,而只是一个数据,因此重命名变换器不会在这里适用。
您需要做的是告诉宏扩展器在将其放入引号并将其转换为基准之前展开food
。 Racket的宏扩展器包含此功能[local-expand
],如果您将其与#:when
(syntax/parse
的{{3}}版本)结合使用,可以让宏首先评估food
。
总而言之,您的代码如下:
#lang racket
(require (for-syntax syntax/parse))
(define-syntax lunch (make-rename-transformer #'sandwich))
(define-syntax (eat stx)
(syntax-parse stx
[(_ food)
#:with expanded-food (local-expand #'food 'expression #f)
#''(eating expanded-food)]))
(eat lunch)
当你运行它时,你得到:
'(eating sandwich)