49

私はScalaを初めて使用し、2.9.1を使用しており、部分関数の使用方法に頭を悩ませようとしています。私はカレー関数の基本を理解しており、部分関数は2naryなどのカレー関数のようなものであることを知っています。お分かりのように、私はこれで少し緑です。

XMLフィルタリングのような特定のケースでは、関数を部分的に実行できることが非常に有利であるように思われるので、それらの使用方法をよりよく理解することを望んでいます。

RewriteRule構造体を使用する関数がありますが、2つの引数で機能する必要がありますが、RewriteRule構造体は1つ、または部分関数のみを取ります。これは私がそれが役立つと思っているケースの1つだと思います。

アドバイス、リンク、知恵の言葉などは大歓迎です!

これまでの答えは素晴らしく、私が持っているいくつかの根本的な誤解を解消しました。彼らは私が苦労しているところも説明していると思います-もう少し具体的な新しい質問を投稿することは役立つと思うので、私もそうします。

4

2 に答える 2

144

部分関数は、渡す可能性のある型の値のサブセットに対してのみ有効な関数です。例えば:

val root: PartialFunction[Double,Double] = {
  case d if (d >= 0) => math.sqrt(d)
}

scala> root.isDefinedAt(-1)
res0: Boolean = false

scala> root(3)
res1: Double = 1.7320508075688772

これは、関数が定義されているかどうかを確認する方法を知っている場合に役立ちます。たとえば、次のように収集します。

scala> List(0.5, -0.2, 4).collect(root)   // List of _only roots which are defined_
res2: List[Double] = List(0.7071067811865476, 2.0)

これは、本当に 1 つが必要な場所に 2 つの引数を配置するのに役立ちません

対照的に、部分的に適用された関数は、その引数の一部が既に入力されている関数です。

def add(i: Int, j: Int) = i + j
val add5 = add(_: Int,5)

これで、必要な引数は 2 つではなく、1 つの引数 (5 を加算するもの) だけになりました。

scala> add5(2)
res3: Int = 7

この例から、その使用方法を確認できます。

しかし、これらの 2 つの引数を指定する必要がある場合でも、これではうまくいきません。mapたとえば、 を使用したい場合、1 つの引数の関数を指定する必要がありますが、2 つの異なるものを追加する必要があります。さて、あなたはすることができます

val addTupled = (add _).tupled

これは、関数を部分的に適用し (実際には、何も入力されていないため、メソッドから関数を作成するだけです)、個別の引数をタプルに結合します。単一の引数が必要な場所でこれを使用できるようになりました (型が正しいと仮定します)。

scala> List((1,2), (4,5), (3,8)).map(addTupled)
res4: List[Int] = List(3, 9, 11)

対照的に、カリー化はまた別のものです。フォームの関数を に(A,B) => C変換しA => B => Cます。つまり、複数の引数を持つ関数を指定すると、それぞれが 1 つの引数を取り、1 つ短いチェーンを返す関数のチェーンが生成されます (一度に 1 つの引数を部分的に適用すると考えることができます)。

val addCurried = (add _).curried

scala> List(1,4,3).map(addCurried)
res5: List[Int => Int] = List(<function1>, <function1>, <function1>)

scala> res5.head(2)   // is the first function, should add 1
res6: Int = 3

scala> res5.tail.head(5)   // Second function should add 4
res7: Int = 9

scala> res5.last(8)  // Third function should add 3
res8: Int = 11
于 2011-12-28T00:21:40.267 に答える
36

Rex Kerr の説明は非常に優れており、そこにも驚きはありません。問題は明らかに部分的な機能部分的に適用された機能を混同しています。なんにせよ、私は Scala を学んだときに同じように混乱しました。

しかし、質問は部分関数に注意を向けているので、私はそれらについて少し話したいと思います。

部分関数はすべての入力に対して定義されていない関数であると多くの人が言います。これは数学には当てはまりますが、Scala には当てはまりません。Scala では、すべての入力に対して関数が定義されていない場合もあります。実際、部分関数は関数から継承されるため、関数にはすべての部分関数も含まれるため、それは避けられません。

他の人はメソッドについて言及していますisDefinedAtが、これは確かに違いですが、主に実装に関するものです。これは本当なので、Scala 2.10 はおそらく に依存しない「高速部分関数」とともにリリースされるでしょうisDefinedAt

applyまた、一部の人々は、部分関数のメソッドが関数のメソッドとは異なることを行うことをほのめかすことさえありapplyます。たとえば、定義された入力に対してのみ実行するなどです。これは真実からかけ離れたものではありません。apply方法は全く同じです。

部分関数が実際に到達するのは、別のメソッドです: orElse. isDefinedAt部分関数は実際には次のいずれかを実行するためのものであるため、これは部分関数のすべての使用例を よりもはるかにうまくまとめています。

  • 部分関数の連鎖 (これが実際orElseに行われていることです)。これにより、各部分関数で入力が試行され、そのうちの 1 つが一致するまで試行されます。
  • 部分関数が一致しない場合、例外をスローする代わりに別のことを行います。これは、orElse.

すべてが簡単に実装できると言っているわけではありませorElseん。念のため。部分関数は、入力が定義されていないときに何か他のことを行うことに関するものだと言っているだけです。

于 2011-12-28T01:37:25.407 に答える