私は、算術などの基本機能をSchemeの継続通過スタイルに変換する方法を理解しています。 しかし、関数に再帰が含まれる場合はどうなりますか?例えば 、スキーム - 継続通過スタイルへの変換
(define funname
(lambda (arg0 arg1)
(and (some procedure)
(funname (- arg0 1) arg1))))
は私にアドバイスをお願いします。 ありがとうございます。
私は、算術などの基本機能をSchemeの継続通過スタイルに変換する方法を理解しています。 しかし、関数に再帰が含まれる場合はどうなりますか?例えば 、スキーム - 継続通過スタイルへの変換
(define funname
(lambda (arg0 arg1)
(and (some procedure)
(funname (- arg0 1) arg1))))
は私にアドバイスをお願いします。 ありがとうございます。
(define (func x y k)
(some-procedure
(lambda (ret)
(if ret
(- x 1
(lambda (ret)
(func ret y k)))
(k #f))))
あなたは継続への唯一の明示的な呼び出しが(k #f)
である理由であるベースケースを、欠けています。ベースケースがある場合は、ベースケースの戻り値も継承に渡します。たとえば:継続とCPSの良い説明があり
(define (func x y k)
(zero? x
(lambda (ret)
(if ret
(k y)
(some-procedure
(lambda (ret)
(if ret
(- x 1
(lambda (ret)
(func ret y k)))
(k #f))))))))
場所の一つは、KrishnamurthiのPLAI本です。関連するパート(VII)は本の他の部分に依存しないので、そこにすぐにジャンプすることができます。具体的には、手動でコードをCPSに変換し、再帰関数に取り組むという拡張例があります(第17章の第1部)。
さらに、私のクラスのためにこのテキストのextended versionを書きました。これは、より多くの例とその件に関する詳細があります。 PLAIのテキストに加えて、私はジェネレータの実装、あいまいな演算子のような継続の一般的な使用をカバーします。 (しかしPLAIは、私のテキストでカバーしていない実装戦略についての議論を続けています。)
これは、クリス・ジェスター・ヤングの答えを部分的に重複しています。
はCPSでは、あなたが探しているの違いは、(おおよそ)これら二つのものの間にある:
後者は、Chrisの例でラムダがやっていることです。基本的に、ラムダを評価するとクロージャが作成され、これらのクロージャは、ダイレクトスタイルのプログラムの実行時にスタックフレームが行うのと同じ仕事を行うために使用されます。スタックフレーム内の戻りアドレスの代わりに、クロージャーには継続機能のバインディングが含まれており、クロージャーのコードはこれを呼び出します。