由于某种原因,以下宏将无法使用引号引起作用。
*nbIsGranted
第二种情况为何失败,我感到很惊讶。
在两种情况下,都会打印以下调试信息。
(define-syntax expand
(lambda (stx)
(syntax-case stx (break)
[(_ k () (ys ...)) (begin (println (syntax->datum #'(ys ...))) #'(ys ...))]
[(_ k ((break) xs ...) (ys ...)) #'(expand k (xs ...) (ys ... (k (void))))]
[(_ k ((es ...) xs ...) (ys ...)) #'(expand k (xs ...) (ys ... (expand k (es ...) ())))]
[(_ k (a xs ...) (ys ...)) #'(expand k (xs ...) (ys ... a))])))
(define-syntax loop
(syntax-rules ()
[(_ e es ...)
(call/cc (lambda (k)
(let l ()
(expand k (begin e es ...) ())
(l))))]))
(loop (list 1 (break)))
;; => works fine
(loop (quasiquote (1 (unquote (break)))))
;; => break: unbound identifier in module in: break
请注意,在;; case 1
'(begin (expand k (list 1 (break)) ()))
'(list 1 (k (void)))
;; case 2
'(begin (expand k `(1 ,(break)) ()))
'`(expand k (1 ,(break)) ())
扩展后的情况2的输出中,其余quasiquote
并未扩展。
不确定为什么会这样。
谢谢
答案 0 :(得分:2)
问题是宏扩展器无法扩展quote
或quasiquote
下出现的宏调用。例如:
(define-syntax-rule (pipe) "|")
> (quote (pipe))
'(pipe) ; not "|"
> (quasiquote (pipe))
'(pipe) ; not "|"
这可以通过直接在编译时对语法对象进行递归来解决,而不是通过返回一个带有宏调用的语法对象来进行递归。
通常,翻译如下代码:
(define-syntax expand
(lambda (stx)
(syntax-case stx literals
cases
[pattern #'(.... (expand stuff) ...)]
cases)))
输入如下代码:
(begin-for-syntax
(define (expand stx)
(syntax-case stx literals
cases
[pattern #`(.... #,(expand stuff) ...)]
cases)))
在特定情况下,您可能希望expand
是3参数函数,该函数在编译时完全运行并重复出现。
(begin-for-syntax
(define (expand k xs ys)
(with-syntax ([(ys ...) ys])
(syntax-case xs (break)
[() (begin (println (syntax->datum #'(ys ...))) #'(ys ...))]
[((break) xs ...) (expand k #'(xs ...) #'(ys ... (k (void))))]
[((es ...) xs ...) (expand k #'(xs ...) #`(ys ... #,(expand k #'(es ...) #'())))]
[(a xs ...) (expand k #'(xs ...) #'(ys ... a))]))))
然后您可以在loop
宏的实现中调用此编译时函数:
(define-syntax loop
(lambda (stx)
(syntax-case stx ()
[(_ e es ...)
#`(call/cc (lambda (k)
(let l ()
#,(expand #'k #'(begin e es ...) #'())
(l))))])))
我希望上面的编译时函数可以帮助您理解宏的可能。但是,对于loop
宏,则不需要它。 语法参数提供了一种更简单的方法。
(define-syntax-parameter break
(lambda (stx) (raise-syntax-error #f "cannot be used outside of loop" stx)))
(define-syntax loop
(syntax-rules ()
[(_ e es ...)
(call/cc (lambda (k)
(define (break-function) (k (void)))
(syntax-parameterize ([break (make-rename-transformer #'break-function)])
(let l ()
(begin e es ...)
(l)))))]))
实际上,像这样的loop
宏是论文Keeping it Clean with Syntax Parameters section 4中使用的示例之一,称为forever
,其中它称为中断语法参数abort
。