我有这段代码:
(define (prog1 x y)
(let ([rel (related x y)])
(cond
[(null? rel) (list x)]
[else (cons x (map (lambda (d) (prog1 (neighbour d) y)) rel))])))
我想要做的是尝试使其尾递归。我知道我需要做类似的事情:
(define (prog1 x y)
(prog1-iter x y `()))
(define (prog1-iter x y acc)
(...
))
但我不确定如何从我的代码转到此代码...我认为这是因为原文中有一张地图,我不确定如何将其合并到prog1-iter
中。有人能指出我正确的方向!
答案 0 :(得分:4)
对于本质上迭代的事物,尾递归很容易编写。您的函数可能会多次调用自身,因此不会很简单。然而,任何程序都可以迭代(例如你的计算机是一个巨大的迭代机器),所以它可以完成。
首先,您的函数不是直接递归(即prog1
不直接调用自身)。相反,prog1
调用map
,然后调用你给它的lambda(可能是多次),然后调用prog1
;所以这是间接的。对map
的呼叫不是尾部呼叫;从map
到lambda的调用当然不是尾调用(可能需要不止一次调用它);从lambda到prog1
的调用是一个尾调用。
因此,当你要求它是“尾递归”时,我不确定你究竟需要什么。您是否希望从prog1
到其自身的呼叫链中的每个呼叫都是尾部呼叫?或者你想让程序中的每一个电话都是尾调用吗?存在map
的“尾递归”版本,但它们只是“从map
到map
的调用的尾递归,而不是对映射函数的调用,所以它们是对你的情况没用。
将程序中的每个调用作为尾调用的一般方法称为continuation-passing style。基本上,每个函数都需要一个额外的函数参数,即“continuation”。您不是对函数进行非尾调用,而是对其进行尾调用,并向其传递一个指定如何处理函数调用结果的延续。基本上,继续将包含非尾部调用之后的原始函数的“其余部分”,并且它将原始非尾部调用的“返回结果”作为参数。我将把它作为练习如何将你的程序转换为CPS。