Recursion 当我使用省略号递归时,为什么代码会冻结?

Recursion 当我使用省略号递归时,为什么代码会冻结?,recursion,racket,Recursion,Racket,它看起来不像是无限递归的,因为我有一个基本情况,每个递归调用都使用一个较小的列表arg1 #lang racket (define a '("Hat" "Shoes")) (define b '("Coat" "Hat")) (define c '("Shirt" "Pants")) (define-syntax func (syntax-rules () ((func arg1 arg2 ... n) (if (or (empty? arg1) (empty? a

它看起来不像是无限递归的,因为我有一个基本情况,每个递归调用都使用一个较小的列表
arg1

#lang racket

(define a '("Hat" "Shoes"))

(define b '("Coat" "Hat"))

(define c '("Shirt" "Pants"))

(define-syntax func
  (syntax-rules ()
    ((func arg1 arg2 ... n)
     (if (or (empty? arg1) (empty? arg2) ...)
         empty
         (if (or (member (first arg1) arg2) ...)
             (cons (string-append n "." (first arg1)) (func (rest arg1) arg2 ... n))
             (cons (first arg1) (func (rest arg1) arg2 ... n))
             )
         )
     )
    )
  )

(func a b c "prefix")

您可以定义宏
func

然后使用宏:
(func a b c“prefix”)
。 使用宏时,宏扩展器将查找定义并将使用与输入模式匹配,并使用模板生成扩展

此处
(func a b c“prefix”)
(func arg1 arg2…n)
匹配。 因此
arg1=a、arg2=(bc)和n=“prefix”

现在使用模板。在模板内部,我发现:

 (func (rest arg1) arg2 ... n))
让我们填写:

 (func (rest a) b c "prefix"))
当然,模板的其余部分也已填充。 现在,由于宏的输出使用了
func
宏扩展器 现在需要扩展新用法:
(func(resta)bc“prefix”)
。 该扩展的输出将包含
(func(rest(resta))bc“前缀”)
(以及更多内容)。宏扩展器现在展开该表达式并获取
(func(rest(rest(rest a)))bc“前缀”)


问题不在于
func
使用
func
,而是
func
的参数大小没有减小。这表明在编写递归宏时必须小心

不要为此使用宏。宏应该用于生成代码,但这里不需要这样做。尤其要小心使用那些会递归扩展的宏!正如soegaard有益地指出的,在本例中,宏正在无限扩展,生成无限量的代码。这显然是非常糟糕的

请记住,宏在编译时运行,而不是在运行时,因此宏的扩展不可能依赖于运行时值。因此,您的“基本情况”在宏上下文中没有意义:从宏的角度来看,它没有停止扩展的点

你想要的是一个普通的旧变量函数。在Racket/Scheme中执行此操作的语法如下所示:

(define (f . args)
  ; do something with args
  )

在上面的示例中,
args
将绑定到一个列表,其中包含提供给
f
的所有参数。您可以使用它作为函数实现
func
。如果您还想要
语法规则
提供的更具声明性的模式匹配功能,您应该查看
匹配

请不要为此使用宏
func
应该是一个函数。这只会不必要地大幅增加代码大小。我似乎很难让函数接受省略号,也无法复制我试图用这个宏完成的任务。甚至可能吗?我可以通过什么方式实现代码的目的?谢谢你。你能用语言说明你的意图吗?你能举一些输入和输出的例子吗?