Functional programming 方案中的尾部递归计数函数

Functional programming 方案中的尾部递归计数函数,functional-programming,scheme,Functional Programming,Scheme,函数应该是尾部递归的,并且从1计数到指定的数字。我想我已经很接近了。以下是我所拥有的: (define (countup l) (if (= 1 l) (list l) (list (countup (- l 1)) l ) ) ) 但是,这显然会返回一个包含嵌套列表的列表。我尝试使用append函数代替第二个列表,但没有成功。有什么指导吗?这里是您的代码的工作版本,它以正确的顺序返回列表(我将l替换为n):

函数应该是尾部递归的,并且从1计数到指定的数字。我想我已经很接近了。以下是我所拥有的:

(define (countup l)
  (if (= 1 l) 
      (list l)
      (list
       (countup (- l 1))
       l
       )
    )
  )

但是,这显然会返回一个包含嵌套列表的列表。我尝试使用append函数代替第二个列表,但没有成功。有什么指导吗?

这里是您的代码的工作版本,它以正确的顺序返回列表(我将
l
替换为
n
):

遗憾的是,这段代码有一个问题:它不是尾部递归的。原因是对
countup
的递归调用不在尾部位置。它不在尾部位置,因为我正在追加
(countup(-l 1))
,所以尾部调用是
append
(或者
list
,当
n=1
)而不是
countup
。这意味着这段代码是一个正常的递归函数,但却是一个尾部递归函数

查看维基百科上的这篇文章,可以找到一个更好的例子,说明为什么它不是尾部递归

要使其尾部递归,您需要一个累加器负责累加计数的值。这样,您就可以将递归函数调用置于尾部位置。看看我给你的链接有什么不同


如果您需要更多详细信息,请随时回复。

这里有一个不正确的解决方案:

(define (countup n)
  (define (help i)
    (if (<= i n)
        (cons i (help (+ i 1)))
        '()))
  (help 1))
注意事项:

  • 此解决方案更好,因为可以立即评估对
    cons
    的调用,因此此函数是尾部递归优化(TCO)的候选函数,在这种情况下,堆栈空间不会成为问题
  • help
    向后递归数字,从而避免了使用
    append
    ,这可能非常昂贵

假设这是一个学习练习,你想要这种行为:

(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的内部调用中,您需要更改在edge case中检查的参数,以使其更接近该edge case,您需要更改另一个参数,使其更接近最终要返回的值。

您应该使用辅助函数来实现此问题的尾部递归解决方案(“循环”函数),并使用额外的参数来累积答案。大概是这样的:

(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)))))

它应该返回什么?n个元素的列表,按升序从1到n,其中n是输入?是的,没错。按从1到指定数字的升序列出n个元素。对不起,我不太清楚。这不是尾部复发。该函数中的最后一个调用转到“list”而不是“countup”。
(define (countup n)
  (loop n '()))

(define (loop i acc)
  (if (zero? i)
      acc
      (loop (sub1 i) (cons i acc))))
(define (countup n)
  (let loop ((i n)
             (acc '()))
    (if (zero? i)
        acc
        (loop (sub1 i) (cons i acc)))))