3

カリー化された関数の結果は部分的に適用された関数ですか?カリー化のしくみや部分機能適用のしくみは理解できましたが、概念にクロスオーバーがあるかどうかはわかりません。

私の混乱は、Learn you a Haskell for great goodからの次の引用から生じました。これは、 JohnSkeetによるこのブログ投稿に基づく概念の以前の理解と矛盾します。

簡単に言えば、パラメーターが少なすぎる関数を呼び出すと、部分的に適用された関数が返されます。つまり、省略したのと同じ数のパラメーターを受け取る関数です。

例を挙げます(質問は関数型プログラミング全般に関するものですが、F#で)

> let add a b = a + b;;

val add : int -> int -> int

> let inc = add 1;;

val inc : (int -> int)

この例ではinc、部分的に適用された関数ですか?

4

2 に答える 2

3

一般的に、カレーとは、2つの引数の関数を、1つの引数を取り、別の1つの引数の関数を返す関数に変換することを意味します。したがって、最初の引数でカレー関数を呼び出し、次に2番目の引数でこれを呼び出した結果は同等です。両方の引数を使用して元の(カレーなしの)関数を呼び出すこと。クロージャと動的型付け(または型推論)を備えた疑似C言語では、これは次のようになります。

// The original, uncurried function:
function f(a, b) { return 2 * a - b; }

// The curried function:
function g(a) {
    return function(b) {
        return f(a, b);
    }
}

// Now we can either call f directly:
printf("%i\n", f(23, 42));

// Or we can call the curried function g with one parameter, and then call the result
// with another:
printf("%i\n", (g(23))(42));

複数回カリー化することで、マルチ引数関数をネストされた1引数関数のセットに減らすことができます。

Haskellでは、すべての関数は単一引数です。のような構成は、実際には架空のC-with-closuresとf a b c同等です。((f(a))(b))(c)関数に複数の引数を実際に渡す唯一の方法は、タプルを使用することです。たとえば、f (a, b, c)-しかし、カレー関数の構文はより単純で、セマンティクスはより柔軟であるため、このオプションはめったに使用されません。

Haskell Preludeは2つの関数を定義しcurryuncurryこれら2つの表現の間で変換します。curryは型です。つまり、タプルを取り、を返す((a,b) -> c) -> a -> b -> c1つの引数の関数を取り、それを型の関数、つまり関数に変換します。を取り、aを取り、を返す関数を返します。逆を行います。(a, b)ca -> b -> cabcuncurry

部分適用は実際には問題ではありません。f a bこれは、カリー化された関数(eg )があり、チェーン全体を完全に展開する代わりに(eg、f 23 42)、途中で停止し、結果の関数をさらに渡すという状況に付けられた名前let g = f 23です。関数を部分適用するには、カレーする必要があります(部分適用はできませんf (a, b)let g = f (a)が、Haskellでは関数をカレーで書くことがデフォルトであるため、部分適用は簡単で一般的な方法です。

于 2012-06-03T12:24:00.527 に答える
0

簡単な答え:inc部分適用によって得られる関数です。

カリー化された関数の結果は、ターゲット言語(Haskell、F#など)のあるタイプの値であるため、関数である可能性があります(ただし、宣言によっては、整数、ブール値などの場合もあります)。 )。

部分適用について...他の関数を返す関数アプリケーションに付けられた名前ですが、技術的には他のすべての関数アプリケーションと同じです。返す関数が前の引数に基づいていることは必須ではありません。\x -> id たとえば、入力に関係なく、常に恒等関数を取得しますx

于 2012-06-03T12:19:03.027 に答える