私は OOP の非機能的なバックグラウンドを持っているため、継続渡しに関するいくつかのオンライン例を完全に視覚化するのに苦労しています。また、Scheme のような関数型言語では、引数の型や戻り値を指定する必要がないため、その考えが正しいかどうかはわかりません。
C# はラムダをサポートしているため、ウィキペディアの記事から最初の例を取り上げ、それを強い型付けで C# に移植して、パターンがどのように適用されるかを確認しました。
// (Scheme)
// direct function
(define (pyth x y)
(sqrt (+ (* x x) (* y y))))
// rewriten with CPS
(define (pyth& x y k)
(*& x x (lambda (x2)
(*& y y (lambda (y2)
(+& x2 y2 (lambda (x2py2)
(sqrt& x2py2 k))))))))
// where *&, +& and sqrt& are defined to
// calculate *, + and sqrt respectively and pass the result to k
(define (*& x y k)
(k (* x y)))
したがって、pyth&
C# で CPS バージョンを書き直すと、次のようになりました。
// (C#6)
// continuation function signature
delegate double Cont(double a);
// *&, +& and sqrt& functions
static double MulCont(double a, double b, Cont k) => k(a * b);
static double AddCont(double a, double b, Cont k) => k(a + b);
static double SqrtCont(double a, Cont k) => k(Math.Sqrt(a));
// sqrt(x*x + y*y), cps style
static double PythCont(double x, double y, Cont k) =>
MulCont(x, x, x2 =>
MulCont(y, y, y2 =>
AddCont(x2, y2, x2py2 =>
SqrtCont(x2py2, k))));
の代わりにジェネリックを使用することもできdouble
ましたが、シグネチャは長くなります。とにかく、よくわからないのは次のとおりです。
上記の
Cont
署名は正しいですか (つまりFunc<double, double>
)? 継続すべき fn. パラメータを受け入れて処理し、同じ型の値を返しますか?最初に継続について読み始めたとき、この継続関数はコール スタックの各ステップで呼び出されるように感じましたが、上記の例では にのみ渡され
sqrt&
、他のすべての呼び出しは実際には「パスしないラムダ」を取得します。 " 元の継続の中間値。上記の関数の上記のコードは、基本的に に似てk(Math.Sqrt(x * x + y * y))
います。これは、中間の「フック」に関する私の仮定が間違っていることを意味しますか?