在Scheme中的相互递归中获取尾部调用优化

Getting tail call optimization in mutual recursion in Scheme

在MIT / GNU方案(版本9.2)中为oddeven函数开发经典的代码段时,我遇到了一个问题,我的代码不会因大整数值而终止。
首先,我测试了以下代码,该代码同时处理正值和负值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
(define error-message-number"Error. x must be a number")

(define odd?
  (lambda (x)
    (cond
      ((not (integer? x)) error-message-number)
      ((= x 0) #f)
      ((< x 0) (even? (+ x 1))) ;for negatives
      (else (even? (- x 1)))))) ;if number n is odd then n - 1 is even

(define even?
  (lambda (x)
    (cond
      ((not (integer? x)) error-message-number)
      ((= x 0) #t)
      ((< x 0) (odd? (+ x 1))) ;for negatives
      (else (odd? (- x 1)))))) ;if number n is even then n - 1 is odd

呼叫(assert (equal? #f (even? 100000000001)))(assert (equal? #t (odd? -100000000001)))不会在我的机器上终止,例如(assert (equal? #f (even? 1001)))(assert (equal? #t (odd? -1001)))做。
我的第一个想法是代码并未针对正确的尾部递归进行优化,而我没有一个,而是在每个函数中有两个尾部调用。
因此,我决定简化任务,只取正整数,就像这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
(define error-message-positive"Error. x must be a nonnegative number")

(define odd-positive?
  (lambda (x)
    (cond
      ((not (integer? x)) error-message-number)
      ((= x 0) #f)
      ((< x 0) error-message-positive) ;for negatives
      (else (even? (- x 1)))))) ;if number n is odd then n - 1 is even

(define even-positive?
  (lambda (x)
    (cond
      ((not (integer? x)) error-message-number)
      ((= x 0) #t)
      ((< x 0) error-message-positive) ;for negatives
      (else (odd? (- x 1)))))) ;if number n is even then n - 1 is odd

但是此版本对于大整数都不返回。
因此,我有以下相关问题:

  • 特征。 MIT / GNU方案中的相互递归函数是否已完全优化?
  • 诊断。有什么办法可以告诉人们这些功能确实是由Scheme编译器/解释器针对相互尾递归进行了优化的。因此,如何判断问题出在(没有)尾递归优化上,还是其他事情上。
  • 什么是正确的相互尾递归?我的初始代码是否有资格进行优化?我的第二张参赛资格吗?

  • What is proper mutual tail recursion?
  • 就像它们的代码一样,它们都是两个版本。

  • Diagnostics.
  • FTW的经验增长顺序!

    您的诊断可能不正确。特别是在我的机器上的Racket中,代码的预期完成时间为40分钟。而且它似乎确实在整体恒定内存中运行。

    是的,即使在恒定的空间中运行,它仍然需要时间来保持参数大小的线性关系。我怎么知道?我只是在时钟墙上的时间对其进行了测量,并且确实将其缩放为线性即n1幂定律。大约。 (即,无论是1.02还是0.97,它仍然指示线性增长率。这很重要)。

    另请参见:

    • 画家之谜-估计
  • Features. Are mutually recursive functions in MIT/GNU Scheme optimized at all?
  • 必须这样,因为尾调用优化在语言规范中。而且TCO不仅仅是尾递归,据我所知,即使下一个调用的决定是动态的(更不用说是静态的,在您的情况下在代码中也很明显),当一个尾部调用时,它仍然必须在恒定的堆栈空间中运行最终导致再次进入相同的功能。尾部调用是尾部调用,无论调用什么,都必须对其进行优化。我目前没有官方报价。