在 Racket 中,我尝试使用 s-exp 来构建一种新语言。所以构建 if 语句的宏是:
(define-syntax (buildif stx)
(syntax-case stx ()
;split the body (stx) and split into parts
[(_ condition (then-expr ...) (else-expr ...))
;build the if statement
#'(if condition
(begin then-expr ...)
(begin else-expr ...))]))
我遇到的问题是我想使用语法->数据或语法->列表将语法转换为数据来修改语法。但是,我无法使用取消引号拼接来转换 datum->syntax 来插入修改后的值。 我想应用一个宏,它接受一个基准列表并返回一个基准列表,使得 '((+ x y) (- x y)) 给出 '((- x y) (+ x y))。我想使用这个修改后的列表作为 if 语句的值
(define-syntax (rev-if stx) ;modified if
(syntax-case stx ()
[(_ condition (then-expr ...) (else-expr ...))
;convert the syntaxes to datums to manipulate
(let ((con (syntax->datum #'condition))
(newthen (opswap (syntax->list #'(then-expr ...))))
(newelse (opswap (syntax->list #'(else-expr ...)))))
;I want to convert the datums back to syntax to execute
(let ((composed `(if ,con (begin ,@newthen) (begin ,@newelse))))
(datum->syntax #f composed)))]))
如果我使用 datum->syntax 我会收到此错误: if:未绑定的标识符; 另外,没有 #%app 语法转换器绑定在: if
如果我尝试使用:
(syntax/loc stx ;build the syntax for the if
(if ,con
;,@ unquote splicing to place syntax of datums into syntax
(begin ,@newthen)
(begin ,@newelse)))
我收到此错误: 取消引用:不在准引用中:(取消引用 con)
datum->syntax
的第一个参数告诉语法扩展器返回的语法应该具有的词法上下文(哪些标识符应该在范围内)。其传达方式是通过现有的语法对象;第一个参数的词法上下文被复制到返回值。
实现此目的的一种方法是在宏调用处使用词法上下文 (
k
)。
(define-syntax (rev-if stx) ;modified if
(syntax-case stx ()
[(k condition (then-expr ...) (else-expr ...))
;convert the syntaxes to datums to manipulate
(let ((con (syntax->datum #'condition))
(newthen (opswap (syntax->list #'(then-expr ...))))
(newelse (opswap (syntax->list #'(else-expr ...)))))
;I want to convert the datums back to syntax to execute
(let ((composed `(if ,con (begin ,@newthen) (begin ,@newelse))))
(datum->syntax #'k composed)))]))
(define-syntax (rev-if stx)
(define (opswap stx)
(syntax-case stx ()
[(+ . t)
(eq? (syntax->datum #'+) '+)
#`(- . #,(opswap #'t))]
[(- . t)
(eq? (syntax->datum #'-) '-)
#`(+ . #,(opswap #'t))]
[(h . t)
#`(#,(opswap #'h) . #,(opswap #'t))]
[_ stx]))
(syntax-case stx ()
[(_ condition consequent alternative)
#`(if condition
#,(opswap #'consequent)
#,(opswap #'alternative))]))
> (rev-if #t (+ 5 (- 1 1)) (- 1 10))
3
> (rev-if #f (+ 5 (- 1 1)) (- 1 10))
11