如何解决用点尾符号表示的方案递归
我正在尝试进行SICP的练习2.20。它引入了点尾符号。在完成练习之前,我需要帮助您了解我编写的此测试程序有什么问题:
(define (f . b)
(if (null? b) '() (cons (car b) (f . (cdr b)))))
当我在解释器中输入(f 1 2 3)
时,没有得到我期望的(1 2 3)
,而是出现了“ 最大递归深度超过”错误。
我看不到我做错了什么。 b
是列表(1 2 3)
,所以我应该得到(cons 1 (f . (2 3))
=> (cons 1 (cons 2 (f . (3))))
=> (cons 1 (cons 2 (cons 3 (f . ()))))
=> (1 2 3)
。
我怀疑问题在于,点分符号仅适用于define,但是我想编写一个递归函数。我该怎么做?
解决方法
点尾符号可以与define
一起使用,这意味着多余的参数在列表中一起收集。使用OP (define (f . b) ;...)
,在像(f 1 2 3)
这样的函数调用中,b
绑定到函数主体中的列表(1 2 3)
。但是,您不能在函数调用中使用点尾符号。
但是仅从尝试的函数调用(f . (cdr b))
中删除点也是行不通的。问题是(cdr b)
是一个列表,因此在第一次递归调用之后,您有了(f (cdr b))
,这意味着传递给f
的值是列表(cdr b)
,并且由于该函数的定义方式,该列表被收集到另一个列表中并绑定到新函数主体中的b
。
如果初始调用为(f 1 2 3)
,则参数将被收集到一个列表中,以便在第一次调用中将b
绑定到(1 2 3)
。这样(car b)
将是1
,随后的调用将是(f (2 3))
。然后,将参数(2 3)
收集到一个列表中,以便在第二个调用中将b
绑定到((2 3))
。现在(car b)
是(2 3)
,这根本不是想要的。
本书apply
中的稍后部分将被介绍,这为解决难题提供了一条途径:
(define (g . b)
(if (null? b)
'()
(cons (car b) (apply g (cdr b)))))
但是,由于我们还不了解apply
,因此我们必须具有创造力。另一种方法是在f
内定义一个辅助函数,该函数接受一个列表参数而不是任意数量的参数:
(define (f . b)
(define (helper xs)
(if (null? xs)
'()
(cons (car xs) (helper (cdr xs)))))
(helper b))
现在,递归调用到helper
,它期望一个列表参数。
示例互动:
> (g 1 2 3)
(1 2 3)
> (f 1 2 3)
(1 2 3)
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。