渡された関数のパラメーターのマニフェストにアクセスしようとする、次の (役に立たない) 高階関数を検討してください。
def foo[T <: (P1) => Unit, P1](f: T)(implicit p1: Manifest[P1]) {}
うまくコンパイルされる例を次に示します。
def theFunc(i: Int) {}
def foo[T <: (P1) => Unit, P1](f: T)(implicit p1: Manifest[P1]) {}
foo(theFunc _)
2 つのパラメーターの関数もサポートするオーバーロードを追加するとします。
def theFunc(i: Int) {}
def foo[T <: (P1) => Unit, P1](f: T)(implicit p1: Manifest[P1]) {}
def foo[T <: (P1, P2) => Unit, P1, P2](f: T)(implicit p1: Manifest[P1], p2: Manifest[P2]) {}
foo(theFunc _)
..コンパイラはそれほど速くないと言っています:
overloaded method value foo with alternatives:
[error] [T(in method foo)(in method foo)(in method foo)(in method foo)(in method foo)(in method foo)(in method foo)(in method foo) <: (P1, P2) => Unit, P1, P2](f: T(in method foo)(in method foo)(in method foo)(in method foo)(in method foo)(in method foo)(in method foo)(in method foo))(implicit p1: Manifest[P1], implicit p2: Manifest[P2])Unit <and>
[error] [T(in method foo)(in method foo)(in method foo)(in method foo)(in method foo)(in method foo)(in method foo)(in method foo) <: P1 => Unit, P1](f: T(in method foo)(in method foo)(in method foo)(in method foo)(in method foo)(in method foo)(in method foo)(in method foo))(implicit p1: Manifest[P1])Unit
[error] cannot be applied to (Int => Unit)
[error] foo(theFunc _)
[error] ^
[error] one error found
では、マニフェストの暗黙的なパラメーターを削除するとどうなるでしょうか?
def theFunc(i: Int) {}
def foo[T <: (P1) => Unit, P1](f: T) {}
def foo[T <: (P1, P2) => Unit, P1, P2](f: T) {}
foo(theFunc _)
再び正常にコンパイルされます!
いくつかの異なる型の暗黙的なパラメーターを使用するのはどうですか?
def theFunc(i: Int) {}
def foo[T <: (P1) => Unit, P1](f: T)(implicit i: Int) {}
def foo[T <: (P1, P2) => Unit, P1, P2](f: T)(implicit i: Int, s: String) {}
implicit val i = 3
implicit val s = "hi"
foo(theFunc _)
また、正常にコンパイルされます。
ここで何が起こっているか知っている人はいますか?Scala 2.10.0 を実行しています。マニフェストの TypeTags を交換しようとしたところ、同じエラーが発生したため、コンパイラが提供する暗黙的なものに固有のものであると推測しています。
TypeTag が必要なため、T を型パラメーターとして定義することが実際のユースケースに必要であると確信していることに注意してください。以下に提案されている存在型の代替案が機能するとは思いません。
これは、誰かが興味を持っている場合に備えて、私の実際のコードです。これは、Lift で jsonCall を抽象化して、Scala 関数から AnonFunc JsExps を作成するものです。
ありがとう!
更新: Régis Jean-Gilles が推奨するように、存在型を使用できないのはなぜですか?
上記にリンクされている実際の使用例では、渡される関数の TypeTag も必要です。私が渡すのは無名関数ではなく、Function2 を拡張するオブジェクトです。
object MyFunc extends ((Int, String) => JsCmd) {
def apply(myInt: Int, myString: String) = JsCmds.Noop
}
これにより、TypeTag を介して関数のパラメーター名を読み取ることができます ( gistを参照)。
存在型についていくつかのナイーブを行使して、私はこれを試しました:
object MyFunc extends ((Int, String) => Unit) {
def apply(myInt: Int, myString: String) {}
}
def foo[P1, P2, T](f: T forSome { type T <: (P1, P2) => Unit})(implicit tag: TypeTag[T], p1: Manifest[P1], p2: Manifest[P2]) = tag
foo(MyFunc)
もちろん、どちらが得られますか:
<console>:12: error: type parameter not specified
foo(MyFunc)
^
型システムを悪用している場合は今すぐ止めてください。ただし、オーバーロードの元の問題に対する満足のいく答えがない場合、これはコンパイラのバグのように感じませんか?