该函数应该是尾递归的,并从1计数到指定的数字。我觉得我很亲密。这就是我所拥有的:
(define (countup l)
(if (= 1 l)
(list l)
(list
(countup (- l 1))
l
)
)
)
但是,这显然会返回一个包含嵌套列表的列表。我试图使用append函数而不是第二个列表无济于事。有什么指导吗?
答案 0 :(得分:1)
这是一个不正确的解决方案:
(define (countup n)
(define (help i)
(if (<= i n)
(cons i (help (+ i 1)))
'()))
(help 1))
此解决方案:
为什么这是错的?它不是真正的尾递归,因为它创建了一大串cons
调用,无法立即进行评估。这会导致堆栈溢出,以获得足够大的n值。
这是解决此问题的更好方法:
(define (countup n)
(define (help i nums)
(if (> i 0)
(help (- i 1)
(cons i nums))
nums)))
(help n '()))
注意事项:
cons
的调用,因此该函数是尾递归优化(TCO)的候选者,在这种情况下,堆栈空间不会成为问题。help
向后追溯数字,从而避免使用append
,这可能相当昂贵答案 1 :(得分:1)
您应该使用辅助函数来实现此问题的尾递归解决方案(“循环”函数),并使用额外的参数来累积答案。像这样:
(define (countup n)
(loop n '()))
(define (loop i acc)
(if (zero? i)
acc
(loop (sub1 i) (cons i acc))))
或者,您可以使用命名let。无论哪种方式,解决方案都是尾递归的,并且参数用于累积值,请注意递归向后推进,从n
开始并计数回0
,即可每个值依次在列表的开头:
(define (countup n)
(let loop ((i n)
(acc '()))
(if (zero? i)
acc
(loop (sub1 i) (cons i acc)))))
答案 2 :(得分:0)
这是代码的工作版本,它以正确的顺序返回列表(我将l
替换为n
):
(define (countup n)
(if (= 1 n)
(list n)
(append (countup (- n 1)) (list n))))
可悲的是,这段代码存在问题:它不是尾递归的。原因是对countup
的递归调用不在尾部位置。它不在尾部位置,因为我正在追加(countup (- l 1))
的结果,因此尾部调用为append
(list
时为n = 1
而不是countup
{1}}。这意味着这段代码是一个普通的recusrive函数,但它是一个尾递归函数。
从维基百科中查看此link,以获得更好的示例,说明它不是尾部重新驱动的原因。
要使其尾递归,您需要有一个累加器来负责累积计数值。这样,您就可以将递归函数调用放在尾部位置。看看我给你的链接的差异。
如果您需要更多详细信息,请随时回复。
答案 3 :(得分:0)
假设这是一个学习练习,你想要这种行为:
(countup 5) => (list 1 2 3 4 5)
这是一个提示 - 在尾递归函数中,尾部位置的调用应该是自身的(除非是边缘情况)。
由于countup不包含数字列表,因此需要一个带有数字和列表的累加器函数,并返回一个列表。
这是一个模板:
;; countup : number -> (listof number)
(define (countup l)
;; countup-acc : number, (listof number) -> (listof number)
(define (countup-acc c ls)
(if ...
...
(countup-acc ... ...)))
(countup-acc l null))
在对countup-acc的内部调用中,您需要更改在边缘情况下检查的参数,以使其更接近该边缘情况,并且您将需要更改另一个参数以使其更接近你想最终回归的是什么。