2013-10-20 6 views
22

Dеarスカラ座、Scalaでは、「大文字小文字の」匿名関数は実際にどのように機能しますか?

scala> val f1: ((Int, Int)) => Int = { case (a, b) => a + b } 
f1: ((Int, Int)) => Int = <function1> 

scala> val f2: (Int, Int) => Int = { case (a, b) => a + b } 
f2: (Int, Int) => Int = <function2> 

ハァッ!

scala> f1(1, 2) 
res2: Int = 3 

[OK]を...

scala> def takesIntInt2Int(fun: (Int, Int) => Int) = fun(100, 200) 
takesIntInt2Int: (fun: (Int, Int) => Int)Int 

scala> def takesTuple2Int(fun: ((Int, Int)) => Int) = fun(100, 200) 
takesTuple2Int: (fun: ((Int, Int)) => Int)Int 

scala> takesIntInt2Int(f2) 
res4: Int = 300 

scala> takesIntInt2Int(f1) 
<console>:10: error: type mismatch; 
found : ((Int, Int)) => Int 
required: (Int, Int) => Int 
       takesIntInt2Int(f1) 
          ^

scala> takesTuple2Int(f1) 
res6: Int = 300 

scala> takesTuple2Int(f2) 
<console>:10: error: type mismatch; 
found : (Int, Int) => Int 
required: ((Int, Int)) => Int 
       takesTuple2Int(f2) 

右。そして今、これを見てください!

scala> takesTuple2Int { case (a, b, c) => a + b + c } 
<console>:9: error: constructor cannot be instantiated to expected type; 
found : (T1, T2, T3) 
required: (Int, Int) 
       takesTuple2Int { case (a, b, c) => a + b + c } 
            ^

scala> takesIntInt2Int { case (a, b, c) => a + b + c } 
<console>:9: error: constructor cannot be instantiated to expected type; 
found : (T1, T2, T3) 
required: (Int, Int) 
       takesIntInt2Int { case (a, b, c) => a + b + c } 

と同様に、srslyが? o_O両方がrequired: (Int, Int)エラーになります。

なぜこのような匿名機能でcaseを使用するのですか?

答えて

15

Scalaリファレンスのセクション8.5(http://www.scala-lang.org/files/archive/nightly/pdfs/ScalaReference.pdf)を参照してください。式{ case (a, b) => a + b }は、予想されるタイプに基づいて異なって解釈されます。 f1の定義では、それはFunction1[(Int, Int), Int]にキャストされたPartialFunction[(Int, Int), Int]を作成しました。つまりf2の定義では、(Int, Int) => Intを作成しました。つまり、((Int, Int)) => Intです。

これらの2つの解釈は、通常、匿名関数で大文字と小文字を使用する2つの状況に関連しています。

1つは、f1のように、タプルを受け入れ、そのコンポーネントで作業する匿名関数を記述するためのものです。例として、Mapforeachまたはmapメソッドに渡す関数があります。 Map(1 -> 2, 3 -> 4) map { case (k, v) => k + v }

第2は、唯一のパラメータにmatchを行う無名関数を書くためのものです。 f2がこれをやっていますが、有用な方法ではありません。例として、collectに渡される無名関数があります。 List(1, -2, 3) collect { case x if x > 0 => -x }

この2つを組み合わせることができます。つまり、f1のような機能も複雑なマッチングを行うことができます。たとえば、Map(1 -> 2, 3 -> 4) collect { case (k, v) if k < 2 => v }です。

編集:res2はタプル処理のために機能します。アプリケーションがチェックを入力しない場合、コンパイラは失敗する前にタプルのargsをラップしようとします。

しかし、それはアプリケーションのために試されます。あなたが発見したように、それは一般的な変換ではありません。値Function2[A, B, C]Function1[(A, B), C]にアップグレードしようとしません。

+1

'case'キーワードを使用せずにすべてを行うことができれば幸いです。通常の開発者の観点から、FunctionとPartialFunctionの構文の違いはなぜですか? –

+2

@MichałRus正直言って、これはいつも私を少し気にしました。 HaskellとClojureは、関数のパラメータに直接パターンマッチングを表現するための構文がずっと簡単です。 – wingedsubmariner

関連する問題