考虑以下形式:
(call hello 12 12)
(call hello pos len)
(call hello (+ 1 2 3) len)
我想写一个扩展为:
的宏'(call $hello 12 12)
'(call $hello (world $pos) (world $len))
'(call $hello 6 (world $len))
这意味着:
(+ 1 2 3)
变为6
)这是我到目前为止所做的:
#lang racket
(require
(for-syntax racket)
(for-syntax racket/syntax))
(define-syntax (call stx)
(define ($ name)
(format-symbol "$~a" name))
(define (eval-args args)
(map (lambda (a)
(if (identifier? a)
`(world ,($ a)) ;; quote
a)) ;; don't quote
(syntax->list args)))
(syntax-case stx ()
((_ name . args)
#``(call #,($ #'name) #,@(eval-args #'args)))))
(call hello 12 12) ;; '(call $hello 12 12)
(call hello pos len) ;; '(call $hello (world $pos) (world $len))
(call hello (+ 1 2 3) len) ;; '(call $hello (+ 1 2 3) (world $len))
如您所见,未评估表格(+ 1 2 3)
:(
如何才能使我的语法中不是标识符的元素不加引号,其余部分被引用?换句话说,我只是想阻止一些元素(不是标识符的东西)被我的宏引用。
我尝试在不是标识符的参数上使用syntax->datum
,syntax-e
,eval-syntax
甚至eval
,但没有人可以做...
答案 0 :(得分:1)
您需要取消引用简单标识符,但使用,a
会调用语法错误,因此您需要将其拼写出来或以不同方式进行引用:
(define (eval-args args)
(map (lambda (a)
(if (identifier? a)
`(world ,($ a))
(list 'unquote a))) ;; force unquote
(syntax->list args)))
扩张:
`(call $hello ,(+ 1 2 3) (world $len))
也许这是更好的风格:
(define (eval-args args)
(map (lambda (a)
(if (identifier? a)
`'(world ,($ a)) ;; quote
a)) ;; don't quote
(syntax->list args)))
(syntax-case stx ()
((_ name . args)
#``(call #,($ #'name) ,@(list #,@(eval-args #'args))))))
扩展看起来略有不同,但也是如此:
`(call $hello ,@(list (+ 1 2 3) '(world $len)))