Recursion 延续传递样式使事物尾部递归?

Recursion 延续传递样式使事物尾部递归?,recursion,scheme,tail-recursion,towers-of-hanoi,Recursion,Scheme,Tail Recursion,Towers Of Hanoi,在这里问这个很痛苦。确实如此。每次我徒劳地寻找我的问题的答案时,我都看到了。嘲笑我 无论如何,一些地狱般的影响使我试图解决河内的塔。我的第一个解决方案是不完整的,因为它导致使用过多磁盘运行if: (define hanoi (lambda (n from to other) (cond ((< n 0) (error `(Error! Number of disks ,n cannot be less than 0!))) ((= n 0)

在这里问这个很痛苦。确实如此。每次我徒劳地寻找我的问题的答案时,我都看到了。嘲笑我

无论如何,一些地狱般的影响使我试图解决河内的塔。我的第一个解决方案是不完整的,因为它导致使用过多磁盘运行if:

(define hanoi
  (lambda (n from to other)
    (cond ((< n 0)
       (error `(Error! Number of disks ,n cannot be less than 0!)))
      ((= n 0)
       '())
      (else
       (append (hanoi (- n 1)
              from
              other
              to)
           `((,from ,to))
           (hanoi (- n 1)
              other
              to
              from))))))
(定义河内
(λ(从n到其他)
(cond(
我在某个地方读到,延续传球方式可以解决问题。然而,这:

(定义河内cps)
(λ(从n到其他c)
(cond(
CPS不会帮助您提高内存效率,因为执行它只是用匿名函数替换堆栈帧。如果您希望程序使用更少的内存,请尝试回溯搜索(但请注意,您必须小心避免无限的移动序列)。

使用连续传递样式,而不是使用递归调用扩展堆栈空间,您正在执行延续的环境中构建递归定义的lambda。。。换句话说,内存在线路的某个地方用完了。例如,对于一个简单的阶乘算法,您通常会编写如下代码:

(define (factorial x)
    (cond ((eq? x 0) 1))
          ((eq? x 1) 1))
          (else (* x (factorial (- x 1))))))
对于
阶乘的递归定义,堆栈空间将被用来保存在每个递归函数调用中形成的延迟乘法运算的参数。相同函数的延续传递版本如下所示:

(define (factorial x cont)
    (cond ((eq? x 0) (cont 1))
          ((eq? x 1) (cont 1))
          (else (factorial (- x 1) (lambda (y) (cont (* x y)))))))
以前消耗堆栈空间的内容现在已被匿名lambda的环境用完。在这种情况下,lambda的环境中充满了解析
x
cont
值所需的值,每次递归调用
factorial
。由于
cont
本身是一个具有环境的lambda,因此您可以看到内存最终将如何消耗,因为每个lambda continuation都需要在其环境中存储来自上一个factorial调用的lambda。。。这将创建一个递归定义的lambda continuation,其环境基本上是通过递归调用
factorial
累积的所有continuation的递归列表


观察延续传递样式的一种方法是,虽然您基本上已经将函数调用机制转换为尾部递归方法,但延续本身的实际定义本质上是递归的,因此您并没有真正消除算法本身的递归性质。。。换句话说,评估通过尾部递归调用构建的延续需要评估其内部的递归定义的延续,该延续本身具有另一个递归定义的延续,等等。lambda延续的环境最终看起来像一个列表中的列表,等等。在lambda continuation的环境中存储所有这些递归定义都需要内存,因此无论您是通过正常的递归调用约定消耗堆栈上的空间,还是通过在每个lambda continuation中存储递归定义的环境来消耗内存空间,无论哪种方式,最终都会耗尽空间。

啊,因此没有办法绕过内存需求。不,这是递归算法的缺点。。。请记住,真正的“尾部递归”调用约定实际上不是真正的递归算法,因为它可以与循环进行交换。出于好奇,多少磁盘就是太多磁盘?@dyoo for
hanoi
:19个磁盘;对于
河内cps
:15个磁盘
(define (factorial x cont)
    (cond ((eq? x 0) (cont 1))
          ((eq? x 1) (cont 1))
          (else (factorial (- x 1) (lambda (y) (cont (* x y)))))))