2012-03-16 9 views
6

私はSchemeでこのCollat​​z予想を書いた:Schemeでスタックのオーバーフローを引き起こすテール再帰的Collat​​z推測はなぜですか?

(define C 
    (lambda (n) 
    (cond 
    ((eq? n 1) 1) 
    ((even? n) (C (/ n 2))) 
    (else (C (+ (* n 3) 1)))))) 

これは末尾再帰呼び出しで、まだ私は(C 121)を呼び出すとき、私は、スタックオーバーフローを取得:

guile> (trace C) 
(C) 
guile> (C 121) 
[C 121] 
[C 364] 
[C 182] 
[C 91] 
[C 274] 
[C 137] 
[C 412] 
[C 206] 
[C 103] 
[C 310] 
[C 155] 
[C 466] 
[C 233] 
[C 700] 
[C 350] 
[C 175] 
[C 526] 
[C 263] 
[C 790] 
[C 395] 
[C 1186] 
ERROR: Stack overflow 
ABORT: (stack-overflow) 

なぜ正しい末尾再帰でありますオーバーフローが発生しますか?ご覧のとおり、GuileをSchemeインタプリタ(バージョン1.8.7)として使用しています。

+0

関数呼び出しをトレースしないとどうなりますか?別のスキームシステムを使用するとどうなりますか? – knivil

+0

トレースを無効にすることは役に立ちません。ラケットは与えられた例でうまくいく。 –

+7

これはバグかもしれません:その定義はtail-recursiveです。 (しかし、ほとんどのトレースライブラリはtail-recursivenessを破壊します。) –

答えて

2

定義されている手順は、Racketで正常に動作します。それは私のバグ、またはあなたの環境に非常に特有のもののようです。

あなたの問題にはほとんど関係ありませんが、ちょっとしたピッキングがあります。(eq? n 1)の代わりに(= n 1)という数字を使用してください。

0
(define C 
    (lambda (n) 
    (cond 
    ((eq? n 1) 1) 
    ((even? n) (C (/ n 2))) 
    (else (C (+ (* n 3) 1)))))) 

それは常に1を返すようにこれが見えます(または無限ループ - 予想は証明されていないまま)。再帰呼び出しの回りに(+1 ...)を隠している転写エラーはありますか?