Recursion 如何在racket中的宏中引用递归变量
在Drracket中,我的任务是创建一个递归宏,可以接受(边n1->n2 n3),例如,n1、n2和n3是(定义结构节点(名称边))。->表示将第二个节点放入第一个节点的边缘,而->表示以两种方式进行。n1有边n2,n2有边n3,n3有边n2。我的问题在于Drracket递归宏。当一个变量后面有一个椭圆时,例如:(边n1->n2…)在模式匹配器中,我不知道如何只引用n2而不计算椭圆Recursion 如何在racket中的宏中引用递归变量,recursion,macros,racket,Recursion,Macros,Racket,在Drracket中,我的任务是创建一个递归宏,可以接受(边n1->n2 n3),例如,n1、n2和n3是(定义结构节点(名称边))。->表示将第二个节点放入第一个节点的边缘,而->表示以两种方式进行。n1有边n2,n2有边n3,n3有边n2。我的问题在于Drracket递归宏。当一个变量后面有一个椭圆时,例如:(边n1->n2…)在模式匹配器中,我不知道如何只引用n2而不计算椭圆 (define-syntax edges (syntax-rules (-> <->) [(
(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]))
(定义语法边
(语法规则(->)
[(边n1->n2…)
(开始
(设置节点边!n1(cons(n2…(节点边n1)))
(第2条……)]
[(边缘n1 n2…)
(开始
(开始
(设置节点边!n1(cons(n2…(节点边n1)))
(设置节点边!n2…(cons'n1(节点边n2…))
(第2条……)]
[(n1)
(无效)
问题在于您使用的模式,这些模式实际上与n2
紧密相连。也就是说,n2
是其他所有内容的列表。你真正想要的是一种更像:
n1 -> n2 rest ...
这样,..
就绑定到rest
,而不是n2
我还建议使用语法分析
而不是语法规则
。它允许更清晰的模式匹配(以及任意计算。例如,现在您假设n1
和n2
是标识符,但您没有检查它。您的宏还要求->
和
绑定到该宏之外。使用语法解析
,整个过程变得更加清晰:
#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 ....)]))
#朗球拍
(需要(用于语法/解析));)
[(_)
#“(开始)]
[(n1:id->n2:id-rest…)
#“(在此处开始您的代码…”
[(n1:id n2:id rest…)
#“(在此处开始…您的代码…”)
在<代码>的内部。。。。您的代码在这里……阻塞,您可以使用n1
来引用n1:id
,您可以使用n2
来引用n2:id
,最后,您可以使用类似(n2 rest…
的内容来引用以n2:id
开始,以rest…
结束的列表
另外,请注意,通过将
:id
放在模式的末尾,您可以自动检查n1
和n2
是否为标识符。嘿,我刚刚注意到您的SO名称。我也患有慢性抑郁症,我只是想让你知道我们在这里是为了你。