如何在球拍的宏中引用递归变量

时间:2018-10-07 19:46:19

标签: recursion macros racket

在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]))

1 个答案:

答案 0 :(得分:0)

问题在于您使用的模式,实际上括号与n2紧密绑定。那是n2 其他所有内容的列表。您真正想要的是一种类似于以下内容的模式:

 n1 -> n2 rest ...

这样,...被绑定到rest,而不是n2

我还建议使用syntax-parse代替syntax-rules。它允许更清晰的模式匹配(以及任意计算。例如,现在您假设n1n2是标识符,但您没有检查它。您的宏也需要-><->被绑定到该宏之外。有了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放在模式的末尾,可以自动检查n1n2是标识符。