Recursion 如何在racket中的宏中引用递归变量

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 (-> <->) [(

在Drracket中,我的任务是创建一个递归宏,可以接受(边n1->n2 n3),例如,n1、n2和n3是(定义结构节点(名称边))。->表示将第二个节点放入第一个节点的边缘,而->表示以两种方式进行。n1有边n2,n2有边n3,n3有边n2。我的问题在于Drracket递归宏。当一个变量后面有一个椭圆时,例如:(边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]))
(定义语法边
(语法规则(->)
[(边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名称。我也患有慢性抑郁症,我只是想让你知道我们在这里是为了你。