我可以这样定义for
循环的语法:
(require syntax/parse/define)
(define-syntax-parser myfor
[(_ Binding Form1 ...)
#'(for (Binding) Form1 ...)]
)
(myfor (I (range 0 10))
(displayln I)
)
它有效,但是当我向其中添加关键字时,它不符合#:break
关键字中的条件:
(require syntax/parse/define)
(define-syntax-parser myfor
[(_ Binding #:break Break Form1 ...)
#'(for (Binding) Form1 ...)]
)
(myfor (I (range 0 10))
#:break (= I 5)
(displayln I)
)
如何以正确的方式向define-syntax-parser
添加关键字?
有两个部分:
#:break
作为可选关键字#:break
有三种方法:多分支,可选和语法类。
最简单的解决方法是在语法分析器中具有两个分支。一个分支带有关键字,另一个分支没有关键字。
两个分支意味着两个模式要在输入上匹配,两个模板要产生输出。
(define-syntax-parser myfor
[(_ Binding #:break Break Form1 ...)
#'(for (Binding #:break Break) Form1 ...)]
[(_ Binding Form1 ...)
#'(for (Binding) Form1 ...)])
这非常简单明了,但缺点是您要重复自己,为每个分支多次指定for
,Binding
和Form1 ...
,如果添加更多关键字,它将变得更加冗长。] >
~?
另一种方法是在模式中使用~optional
和~seq
来匹配输入,而在模板中使用~?
和~@
来产生输出。
(define-syntax-parser myfor [(_ Binding {~optional {~seq #:break Break}} Form1 ...) #'(for (Binding {~? {~@ #:break Break}}) Form1 ...)])
注意模板中的
~?
在图案中是~optional
的位置,而模板中的~@
在图案中是~seq
的位置。
当输入模式和输出模板之间存在明显的对称性时,此策略是最佳选择。
(begin-for-syntax
(define-splicing-syntax-class maybe-break-clause
[pattern {~seq} #:with (out ...) '()]
[pattern {~seq #:break Break} #:with (out ...) #'(#:break Break)]))
(define-syntax-parser myfor
[(_ Binding mbc:maybe-break-clause Form1 ...)
#'(for (Binding mbc.out ...) Form1 ...)])
在这种情况下,对于#:break
,此策略是过大的,但是如果关键字的行为比简单地传递关键字(如果存在)更为复杂,则可能有必要。
我发现了,我需要在语法中添加〜optional和〜seq: