3

重複の可能性:
関数型プログラミング:カリー化

私はここで無料のF#ウィキブックスを読んでいます:

http://en.wikibooks.org/wiki/F_Sharp_Programming

部分関数とは何かを説明するセクションがあります。F#を使用すると、関数を部分的に使用できると書かれていますが、何が起こっているのか理解できません。例として使用されている次のコードスニペットについて考えてみます。

#light
open System

let addTwoNumbers x y = x + y
let add5ToNumber = addTwoNumbers 5

Console.WriteLine(add5ToNumber 6)

出力は11です。しかし、私はフォローしていません。私の関数'add5ToNumber'はパラメーターを要求しないのに、なぜそれを呼び出してパラメーターを与えることができるのですか?

私は最近F#について学ぶのが本当に好きです、ベイビーステップ!

4

5 に答える 5

3

カリー化は次のようなものです。

addTwoNumbers数値を受け取り、数値を返す数値を受け取る関数を返す関数です。

実際、数値を受け取って数値を返す関数も同様です。これaddTwoNumbers 5がカリー化のしくみです。に割り当てるのでaddTwoNumbers 5、数値を受け取り、数値を返す関数をadd5ToNumber作成します。add5ToNumber

F# で型定義がどのように見えるかはわかりませんが、Haskell では、関数の型定義がこれを明確にしています。

addTwoNumbers :: (Num a) => a -> a -> a

addTwonumbersに、2つのタプルを取るように書いた場合、

addTwoNumbers :: (Num a) => (a, a) -> a

then is は 2 つのタプルを取り、数値を返す関数になるため、add5ToNumberそのまま作成することはできません。

于 2010-11-08T13:40:57.593 に答える
3

基本的に、F# のすべての関数には 1 つのパラメーターがあり、1 つの値を返します。その値は、() で指定されたユニット型にすることができます。これは、他の言語の void と概念が似ています。

複数のパラメーターを持つように見える関数がある場合、F# はそれを、それぞれが 1 つのパラメーターを持つ複数の関数として扱い、必要な結果を得るために "カリー化" されます。したがって、あなたの例では、次のようになります。

let addTwoNumbers x y = x + y

それは実際には2つの異なる機能です。の値を新しい関数のパラメーターのx値に追加する新しい関数を取得して作成します。x新しい関数はパラメーターを受け取り、y整数の結果を返します。

したがって、addTwoNumbers 5 6実際には 11 が返されます。ただし、addTwoNumbers 5構文的にも有効であり、パラメータに 5 を追加する関数が返されます。それが有効な理由add5ToNumber 6です。

于 2010-11-08T13:48:50.287 に答える
2

他の回答に追加するだけで、フードの下で、関数をカリー化するとクロージャーが返されます。

[Serializable]
internal class addToFive@12 : FSharpFunc<int, int>
{
    // Fields
    [DebuggerBrowsable(DebuggerBrowsableState.Never), CompilerGenerated, DebuggerNonUserCode]
    public int x;

    // Methods
    internal addToFive@12(int x)
    {
        this.x = x;
    }

    public override int Invoke(int y)
    {
        return Lexer.add(this.x, y);
    }
}
于 2010-11-08T13:47:24.893 に答える
1

これはeta-expansionとして知られています: 関数型言語では、

let f a = g a

に等しい

let f = g

これは数学的に理にかなっています.2つの関数がすべての入力に対して等しい場合、それらは等しい.

あなたの例でgaddTwoNumbers 5、あなたが書いたコードは次のものと完全に同等です:

let add5toNumber y = addTwoNumbers 5 y

それらが異なるいくつかの状況があります。

  • 場合によっては、省略した場合、型システムがy普遍的に限定されたものとして認識しないことがあります。
  • (パラメーターが 1 つだけの場合addTwoNumbers 5) 副作用 (コンソールに 5 を出力するなど) がある場合、eta 拡張バージョンは呼び出されるたびに 5 を出力し、eta-reduced バージョンは定義時にそれを出力します。これは、addTwoNumbers 5一度しか実行できない重い計算が含まれる場合、パフォーマンスに影響を与える可能性もあります。
  • Eta-reduction は、ラベルやオプションの引数にはあまり適していません (ただし、それらは F# には存在しないため、問題ありません)。

そしてもちろん、新しい関数名が非常に読みやすいものでない限り、省略された引数の名前を提供することは常に読者にとって大きな助けになります。

于 2010-11-08T13:48:28.220 に答える
0

addTwoNumbersx2 つの引数 (および)を受け入れますy

add5ToNumber引数が 1 つだけの呼び出しの出力に割り当てられaddTwoNumbersます。これにより、最初の引数を「保存」し ( x -> 5)、別の引数を 1 つ受け入れる( ) 別の関数が生成されyます。

6 をadd5ToNumberに渡すと、保存されたx(5) と指定されたy(6) が に渡されaddTwoNumbers、11 になります。

于 2010-11-08T13:40:49.580 に答える