web-dev-qa-db-ja.com

Scala-でどのように機能しますか?

私はScalaを初めて使い、2.9.1を使用しています。また、部分関数の使用方法を頭に入れようとしています。私はカリー化された関数の基本的な理解があり、部分的な関数はカリー化された関数のようなものであり、2項のみであることがわかっています。あなたが言うことができるように、私はこれで少し緑です。

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

RewriteRule構造体を使用する関数がありますが、2つの引数を使用する必要がありますが、RewriteRule構造体は1つしか使用できません。OR部分関数。私はそれが役立つことを考えています。

アドバイス、リンク、知恵などを歓迎します!

これまでの回答は優れており、私が持っているいくつかの基本的な誤解を解消しました。彼らは私が苦労している場所も説明していると思う-もう少し具体的な新しい質問を投稿すると役立つかもしれないと思うので、私もそれをやります。

47
PlexQ

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

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)

これはnotであり、2つの引数を本当に必要な場所に配置するのに役立ちます。

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

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

これで、2つではなく1つの引数(5を追加するもの)のみが必要になります。

scala> add5(2)
res3: Int = 7

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

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

val addTupled = (add _).tupled

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

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

対照的に、curryingは再び異なります。それは(A,B) => C into 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
142
Rex Kerr

Rex Kerrの説明は非常に優れており、驚きもありません。問題は、明らかに部分関数部分的に適用された関数を混同していることです。価値があるものは何でも、私はScalaを学んだときに同じ混乱を自分でしました。

ただし、この質問は部分的な機能に注意を引くので、少しお話ししたいと思います。

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

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

また、一部の人々は、部分関数のapplyメソッドは、定義された入力に対してのみ実行するなど、関数のapplyメソッドとは異なることを行うことを暗示しています。真実。 applyメソッドは正確に同じです。

部分関数が実際に到達するのは、別のメソッドorElseです。部分関数は実際には次のいずれかを実行するものなので、部分関数のすべてのユースケースはisDefinedAtよりもはるかに優れています。

  • 部分関数の連鎖(これはorElseが行うことです)。その結果、いずれかの部分関数が一致するまで入力が試行されます。
  • orElseを使用してその異なることを連鎖させると、例外をスローする代わりに、部分的な関数が一致しない場合に異なることを行います。

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

35