Getting tail call optimization in mutual recursion in Scheme
在MIT / GNU方案(版本9.2)中为
首先,我测试了以下代码,该代码同时处理正值和负值:
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 |
呼叫
我的第一个想法是代码并未针对正确的尾部递归进行优化,而我没有一个,而是在每个函数中有两个尾部调用。
因此,我决定简化任务,只取正整数,就像这样:
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 |
但是此版本对于大整数都不返回。
因此,我有以下相关问题:
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不仅仅是尾递归,据我所知,即使下一个调用的决定是动态的(更不用说是静态的,在您的情况下在代码中也很明显),当一个尾部调用时,它仍然必须在恒定的堆栈空间中运行最终导致再次进入相同的功能。尾部调用是尾部调用,无论调用什么,都必须对其进行优化。我目前没有官方报价。