我正在尝试编写两个单独的尾递归函数来计算列表的长度,并且我给出了这些限制:
编写一个尾递归的版本lengtht
,并根据需要使用外部(非嵌套)辅助功能
编写第二个版本,lengtht2
,不使用其他顶级函数。该函数仍然应该是尾递归的,并且可以使用您想要的任何本地绑定
我是新手,我理解尾递归的一般形式是:
(define (func x)
(cond (end-test-1 end-value-1)
(end-test-2 end-value-2)
(else (func reduced-x))))
我对如何做到这一点感到有点困惑
答案 0 :(得分:2)
本质上,尾递归函数会一直调用自身直到达到最终状态。然而,与“常规”递归不同,它将中间答案传递给自身,直到它到达结尾。
一个例子是:
(define (find-length i lst)
(if
(null? lst) i
(find-length (+ i 1) (cdr lst))))
该函数有两个值:i
,它跟踪到目前为止列表的长度,lst
,我们计算的元素列表。i
。 i
,就所有意图和目的而言,是我们对列表中元素的运行计数。因此,如果我们调用此方法,我们将要将null?
初始化为0来调用它。
首先,我们检查列表是否为空。 (i
)如果列表为空,我们可以假设我们已经计算了所有元素,因此我们只返回find-length
,这是我们的运行计数。这是我们的最终条件。
否则,我们再次致电i
。但是,这一次,我们将(cdr lst)
加1,并从列表(find-length 0 (list 2 3 4 3 5 3))
中删除了第一个元素。
例如,假设我们调用这样的函数:
(find-length 1 '(3 4 3 5 3))
(find-length 2 '(4 3 5 3))
(find-length 3 '(3 5 3))
(find-length 4 '(5 3))
(find-length 5 '(3))
(find-length 6 '()) ; end condition, return 6
在我们评估时,程序会递归调用:
{{1}}
This question通常是尾递归的一个很好的参考。
答案 1 :(得分:2)
这看起来像是家庭作业,所以我会给你一些提示,指出你正确的方向,你可以填补空白。试试第一个问题:
(define (loop lst acc) ; receives a list and an accumulator
(cond ((null? lst) <???>) ; if the list is empty return the accumulator
(else (loop <???> <???>)))) ; advance the recursion, +1 to accumulator
(define (length1 lst)
(loop <???> <???>)) ; how should we initialize the iteration?
尝试第二个问题:
(define (length2 lst)
(letrec ((loop <???>)) ; lambda with the same procedure as the previous `loop`
(loop <???> <???>))) ; start the recursion exactly the same as in `length1`
无论如何,想一想:空(空)列表的长度是多少?答案将向您展示如何初始化迭代。对于这两种解决方案,我们使用一个名为acc
的额外参数来跟踪到目前为止的答案,并将它与列表一起传递给循环尾递归过程。