18

どこを見ても、複数のパラメーター リストとカリー化という用語が同じ意味で使用されています。何十ものスタックオーバーフローの質問や、scala-lang.org でさえそれを目にします。 たとえば、このページのタイトルは「Currying」です。そして最初の文は?「メソッドは、複数のパラメーター リストを定義できます。」

それでも、非常に知識のある人は、複数のパラメーター リストとカリー化が同一視されているのを見るとイライラします。この質問への回答を投稿しましたが、Randall Schulz のコメントを見て削除しました。うっかり誤った情報を広めてしまうのではないかと心配したからです。私の理解では、複数のパラメーター リストを持つ関数は必然的にカリー化された関数ですが、その関数のカリー化は他の方法でも実現できます (この質問に対する上位の回答には 4 つの方法がリストされています)。 . その違いをしっかりと理解したい。

これと非常によく似た質問がstackoverflowにたくさんあることは知っていますが、違いを正確に説明する質問は見つかりませんでした。複数のパラメータ リストとカリー化について正確に説明するには、何を理解する必要がありますか?

4

1 に答える 1

24

Haskell は Scala よりもはるかに単純な言語であるため、Haskell の例から始めても問題ありません。Haskell では、すべての関数は数学的な意味での関数です。1 つの引数を取り、1 つの値を返します。Haskell にもタプルがあり、複数のパラメーターを受け取るように見える関数を、タプルから任意の関数として作成できます。例えば:

Prelude> let add = (\(x, y) -> x + y) :: (Int, Int) -> Int
Prelude> add (1, 2)
3

これで、この関数をカリーInt -> Int -> Int化して、 の代わりにtype を持つ関数を取得できます(Int, Int) -> Int

Prelude> let curriedAdd = curry add

これにより、関数を部分的に適用できます。たとえば、次のようになります。

Prelude> let add3 = curriedAdd 3
Prelude> add3 1
4

したがって、カリー化のきれいな定義があります。これは、引数としてタプル (特にペア) を持つ関数を取り、ペアの最初の型を引数として取り、2 番目の型から関数を返す関数を返す関数です。ペアを元の戻り型に入力します。これは、これを言うための単なる言葉遣いです:

Prelude> :t curry
curry :: ((a, b) -> c) -> a -> b -> c

さて、次は Scala です。

Scala では、タプル引数を取る関数を使用することもできます。Scala には、複数の引数 (以上) を取る「関数」もありますFunction2。これらは (紛らわしいことに) 異なる種類の動物です。

Scala には関数とは異なるメソッドもあります (ただし、これらはeta 展開によって多かれ少なかれ自動的に関数に変換できます)。メソッドには、複数のパラメーター、タプル パラメーター、または複数のパラメーター リストを含めることができます。

では、このコンテキストで何かをカリー化しているとはどういう意味でしょうか?

最も文字通り、カリー化は a Function2(および up) を使用して行うものです。

scala> val add: Function2[Int, Int, Int] = (x: Int, y: Int) => x + y
add: (Int, Int) => Int = <function2>

scala> val curriedAdd = add.curried
curriedAdd: Int => (Int => Int) = <function1>

scala> val add3 = curriedAdd(3)
add3: Int => Int = <function1>

これは Haskell のケースで見たものとほぼ同じですが、Haskell には適切に存在しない複数の引数を持つ関数をカリー化している点が異なります。

これは、カレーという単語が実際に Scala 標準ライブラリに表示される唯一のコンテキストであると確信しています (コンパニオン オブジェクトuncurriedに付随するものは数えません)。ただし、Scala がメソッド、関数、など (誤解しないでください。私は Scala が大好きですが、言語のこの部分は完全な災害です)、次の文脈でもこの言葉を適用するのはかなり理にかなっているように思えます。Function

def add(x: Int, y: Int) = x + y
def curriedAdd(x: Int)(y: Int) = add(x, y)

ここでは、2 つのパラメーターを受け取るメソッドを、複数のパラメーター リストを持つメソッドに変更しました。<em>それぞれのパラメーターは 1 つのパラメーターのみを受け取ります (この最後の部分が重要です)。

実際、言語仕様もこの文脈でこの用語を使用しており、以下を「単一のカリー化された関数定義」と説明しています。

def func(x: Int)
        (y: Int) = x + y

(もちろん、これは関数ではなくメソッドであるため、非常に混乱します。)

要約すると、複数のパラメーター リストは Scala でカリー化を実装する 1 つの方法ですが、複数のパラメーター リストを持つすべてのメソッドがカリー化されるわけではなく、各パラメーター リストが 1 つのパラメーターを持つメソッドのみがカリー化されます。とにかく、すべての用語はかなりどろどろしているので、正しく理解することについてあまり心配する必要はありません。

于 2013-11-11T21:36:55.917 に答える