在Drracket中,我的任务是创建一个递归宏,该递归宏可以使用(边n1-> n2 <-> n3),例如,n1,n2和n3是(定义结构节点(名称边)) 。 ->表示将第二个节点置于第一个节点的边缘,而<->表示同时进行这两种方式。因此n1将具有边n2,n2将具有边n3,n3将具有边n2。我的问题在于Drracket递归宏。如果在模式匹配器中有一个带椭圆的变量,例如ex:(edges n1-> n2 ...),我不知道如何在不评估椭圆的情况下仅引用n2。
(define-syntax edges
(syntax-rules (-> <->)
[(edges n1 -> n2 ...)
(begin
(set-node-edges! n1 (cons (n2 ...) (node-edges n1)))
(edges n2 ...))]
[(edges n1 <-> n2 ...)
(begin
(begin
(set-node-edges! n1 (cons (n2 ...) (node-edges n1)))
(set-node-edges! n2 ... (cons 'n1 (node-edges n2 ...))))
(edges n2 ...))]
[(edges n1)
void]))
答案 0 :(得分:0)
问题在于您使用的模式,实际上括号与n2
紧密绑定。那是n2
是其他所有内容的列表。您真正想要的是一种类似于以下内容的模式:
n1 -> n2 rest ...
这样,...
被绑定到rest
,而不是n2
。
我还建议使用syntax-parse
代替syntax-rules
。它允许更清晰的模式匹配(以及任意计算。例如,现在您假设n1
和n2
是标识符,但您没有检查它。您的宏也需要->
和<->
被绑定到该宏之外。有了syntax-parse
,整个事情变得更加清晰:
#lang racket
(require (for-syntax syntax/parse)) ;; <-- Needed to use syntax-parse
(define-syntax (edges stx)
(syntax-parse stx
#:datum-literals (-> <->)
[(_)
#'(begin)]
[(_ n1:id -> n2:id rest ...)
#'(begin .... your code here ....)]
[(_ n1:id <-> n2:id rest ...)
#'(begin .... your code here ....)]))
在.... your code here ....
块中,您可以使用n1
来引用n1:id
,可以使用n2
来引用n2:id
,最后,您可以使用类似(n2 rest ...)
之类的内容来引用以n2:id
开始并以rest ...
结尾的列表。
另外,请注意,通过将:id
放在模式的末尾,可以自动检查n1
和n2
是标识符。