Functional programming 在scheme中转换具有两个递归调用的函数,使其成为尾部递归函数

Functional programming 在scheme中转换具有两个递归调用的函数,使其成为尾部递归函数,functional-programming,scheme,tail-recursion,Functional Programming,Scheme,Tail Recursion,在我开始之前:是的,这是大学的家庭作业。在我被告知我懒惰和邪恶之前:家庭作业的这一部分是转换我们已经拥有的两个函数,这是第六个 (define (flatten-list a-list) (cond ((null? a-list) '()) ((list? (car a-list)) (append (flatten-list (car a-list)) (flatten-list (cdr a-list)))) (else (cons (car a-

在我开始之前:是的,这是大学的家庭作业。在我被告知我懒惰和邪恶之前:家庭作业的这一部分是转换我们已经拥有的两个函数,这是第六个

(define (flatten-list a-list)
  (cond ((null? a-list) '())
      ((list? (car a-list)) 
       (append (flatten-list (car a-list)) (flatten-list (cdr a-list))))
      (else (cons (car a-list) (flatten-list (cdr a-list))))))
正如您所猜测的那样,该函数会使列表变平,即使它是嵌套的。我对转换的具体问题出现在(list?(cara-list))条件中,在该条件下,我正在执行两个递归调用。我已经做了斐波那契,我可以通过在尾部递归上有两个“acummulator”来完成。然而,我的头脑还没有接受过这方面的训练,还不知道该怎么做

如果给我提示而不是结果,我将不胜感激。谢谢

以下是我的解决方案:

(define (flatten-iter a-list)
  (define (flat-do acc lst-interm lst)
    (cond 
      ((null? lst)
       (reverse acc))
      ((and (list? lst-interm) (not (null? lst-interm)))
       (flat-do acc (car lst-interm) (append (cdr lst-interm) lst)))
      ((not (list? lst-interm))
       (flat-do (cons lst-interm acc) empty lst))
      ((list? (car lst))
       (flat-do acc (car lst) (cdr lst)))
      (else
       (flat-do (cons (car lst) acc) empty (cdr lst)))))
  (flat-do empty empty a-list))

(flatten-iter (list 1 (list 2 (list 3 4 (list 5 empty 6))) 7 8))
=> (1 2 3 4 5 6 7 8)
尾部重现函数要求它们永远不会返回,因此不能使用堆栈来存储程序的状态。相反,您可以使用函数参数在函数调用之间传递状态。因此,我们需要确定如何维持这种状态。因为我们函数的结果是
list?
,所以有必要增加一个
空的
列表;为此,我们使用了
acc
。您可以在上面的
else
分支中看到它是如何工作的。但是我们应该能够处理嵌套列表。在深入研究的同时,我们应该保留嵌套列表的其余元素,以便进一步处理。示例列表:
(列表1(列表2 3)4 5)

(列表2 3)
之前,我们已经在累加器中添加了
1
。因为我们不能使用堆栈,所以我们需要其他地方来存储列表的其余元素。这个地方是
lst
参数,它包含要展平的原始列表的元素。我们可以只
lst
附加到其余元素
(cdr(列表2-3))
,这些元素是
(列表3)
,然后继续使用我们在展平时偶然发现的列表头,即。E(汽车(清单2-3)),它只是
2
。现在,
(and(list?lst interm)(not(null?lst interm))
成功了,因为
平面do
被称为:

(flat-do (list 1) (list 2 3) (list 4 5))
条件会触发此代码:

(flat-do (list 1) (car (list 2 3)) (append (cdr (list 2 3)) (list 4 5)))
flat do
又是这样叫的:(flat do(列表1)2(列表3 4 5))

条件
(not(list?2))
现在成功,并计算代码
(flat do(cons 2 1)empty(list 3 4 5))


其余处理通过
else
分支完成,直到
lst
null?
反向
acc
上执行。函数然后返回反向累加器。

希望我能够感谢您的快速响应,Yasir。读完后,我确实明白了它在做什么(这很重要),但如果你能告诉我你遵循的思考过程,我将不胜感激。对不起,我要求太多了!非常感谢到目前为止的帮助。我现在要去吃比萨饼了。如果你不介意的话,让我稍后再详细解释:-)Buen provecho:(享受你的晚餐)当你在等Yasir吃完他的比萨饼时:有一种叫做“延续传递样式”(CPS)的通用技术,它可以转换任何代码片段,以便所有调用都处于尾部位置。Matt最近可能有一篇关于CPS转型的博客文章,你可能想看看。Mamsaac:我更新了答案。我同意@John,CPS是一种很好的技术,值得研究。