2011-02-04 4 views
7

Scalaコンパイラは本当に匿名関数のパラメータの型情報をいつ必要としますか?例えばScalaは匿名関数と拡張関数のパラメータ型をいつ必要としますか?

、この機能を持た:

def callOn[T,R](target: T, f: (T => R)) = f(target) 

その後、私はこのようにそれを使用することはできません。

callOn(4, _.toString) 
    => error: missing parameter type for expanded function ((x$1) => x$1.toString) 

と私はむしろ醜いです

callOn(4, (_: Int).toString) 

を指定する必要があります。なぜ私の例は動作しませんが、コレクションクラスのmap、filter、foldLeftなどのメソッドはこの明示的な型を必要としないようです。

答えて

14

トリック推論を入力するためには、反復改良のプロセスとしてそれを考えることです。各パラメータブロックを使用して、タイプパラメータの一部を推論することができ、後続のブロックで使用することができます。だから、次の定義を行いますと呼ばれる

def chain[T,A,B](x: T)(fn1: T=>A)(fn2: A=>B) = fn2(fn1(x)) 

chain(2)(_*10)("xxx"+_) 

は、どのようにこれは推測されているのですか?まず、タイプIntであることが知られているブロック(2)から始めます。

def chain[A,B](x: Int)(fn1: Int=>A)(fn2: A=>B) = fn2(fn1(x)) 

次のパラメータブロックは、我々は今Intするプレースホルダ_の種類を知っているところ、(_*10)です...とIntIntを掛けることは、別のIntを与える:その背中我々が得るTパラメータへの代入。これはオーバーフローが発生しても返される型に当てはまります。極端な場合、例外がスローされる可能性がありますが、例外は型システムの他のすべてのサブクラスであるタイプNothingを持っています。したがってNothingは-Intであり、推測型はIntです。推論A

、方法は次のようになる。

def chain[B](x: Int)(fn1: Int=>Int)(fn2: Int=>B) = fn2(fn1(x)) 

のみB("xxx"+_)から推測することができるが残ります。String + IntStringであるように、この方法は、以下のようになります。また、明示的に完全を期すために示すことができるメソッドの戻り値の型fn2から直接来て、として

def chain(x: Int)(fn1: Int=>Int)(fn2: Int=>String) = fn2(fn1(x)) 

あり
def chain(x: Int)(fn1: Int=>Int)(fn2: Int=>String): String = fn2(fn1(x)) 

あなたはそれを持っていますすべての型が安全に解決され、メソッドが静的に有効であることが証明されています。あなたのケースでは


、あなたはそれがタイプT=>RからRを推測することが可能です前に推論されるタイプTを必要としています。これを行うには、パラメータを2つの別個のブロックに分割し、カレー形式でメソッドを記述する必要があります。

def callOn[T,R](target: T)(f: (T => R)) = f(target) 
6

この質問もここで回答されています

Passing functions for all applicable types around

あなたは二回、正しい種類を推測するために、アカウントに両方のパラメータを取るためにScalaのコンパイラのために...、期待しています。しかし、Scalaでは、1つのパラメータリストから次のパラメータリストへの情報しか使用しませんが、1つのパラメータから次のパラメータへの情報は使用しません。つまり、パラメータfとa [WS:この場合のターゲットとf]は、別のものが何であるかを知ることなく、独立して分析されます。それはカリーバージョンで作業を行うこと

注:

scala> def callOn[T,R](target: T)(f: (T => R)) = f(target) 
callOn: [T,R](target: T)(f: (T) => R)R 

scala> callOn(4)(_.toString) 
res0: java.lang.String = 4 

scala> 
+0

ありがとうございました。この単純なケースがあるとしましょう: 'def callOn4 [R](f:(Int => R))= f(4)'。なぜ私は 'def callOn4(f:(Int => _))= f(4)'と定義すればいいのですか? –

+1

@jpp - ちょっと試してみて、あなたの2番目のバージョンでどのような戻り値の型が推測されるのか... –

関連する問題