我该怎么做这个尾递归?

时间:2012-12-28 17:50:46

标签: scheme

我有这段代码:

(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中。有人能指出我正确的方向!

1 个答案:

答案 0 :(得分:4)

对于本质上迭代的事物,尾递归很容易编写。您的函数可能会多次调用自身,因此不会很简单。然而,任何程序都可以迭代(例如你的计算机是一个巨大的迭代机器),所以它可以完成。

首先,您的函数不是直接递归(即prog1不直接调用自身)。相反,prog1调用map,然后调用你给它的lambda(可能是多次),然后调用prog1;所以这是间接的。对map的呼叫不是尾部呼叫;从map到lambda的调用当然不是尾调用(可能需要不止一次调用它);从lambda到prog1的调用是一个尾调用。

因此,当你要求它是“尾递归”时,我不确定你究竟需要什么。您是否希望从prog1到其自身的呼叫链中的每个呼叫都是尾部呼叫?或者你想让程序中的每一个电话都是尾调用吗?存在map的“尾递归”版本,但它们只是“从mapmap的调用的尾递归,而不是对映射函数的调用,所以它们是对你的情况没用。

将程序中的每个调用作为尾调用的一般方法称为continuation-passing style。基本上,每个函数都需要一个额外的函数参数,即“continuation”。您不是对函数进行非尾调用,而是对其进行尾调用,并向其传递一个指定如何处理函数调用结果的延续。基本上,继续将包​​含非尾部调用之后的原始函数的“其余部分”,并且它将原始非尾部调用的“返回结果”作为参数。我将把它作为练习如何将你的程序转换为CPS。

相关问题