0

渡された関数のパラメーターのマニフェストにアクセスしようとする、次の (役に立たない) 高階関数を検討してください。

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)
                     ^

型システムを悪用している場合は今すぐ止めてください。ただし、オーバーロードの元の問題に対する満足のいく答えがない場合、これはコンパイラのバグのように感じませんか?

4

1 に答える 1

1

最初の質問は、なぜこのような複雑な型パラメーターを使用するのかということです。あなたの例を見ると、これらの定義をうまく変えることができるようです:

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]) {}

はるかに単純な定義に:

def foo[P1](f: P1 => Unit)(implicit p1: Manifest[P1]) {}
def foo[P1, P2](f: (P1, P2) => Unit)(implicit p1: Manifest[P1], p2: Manifest[P2]) {}

後者では、への呼び出しは正常にfooコンパイルされます。

何らかの理由で型が本当に必要な場合T(たとえば、実際のコードが関数を拡張する型を定義しメソッドfooが関数の正確な型に依存するものを返すなど)、存在型に依存できます。

def foo[P1](f: T forSome { type T <: (P1) => Unit})(implicit p1: Manifest[P1]) {}
def foo[P1, P2](f: T forSome { type T <: (P1, P2) => Unit})(implicit p1: Manifest[P1], p2: Manifest[P2]) {}

そもそもなぜエラーが発生するのかについては、正直言って決定的な説明はありません。


更新:OK、下のコメントから、私の直感は良かったようです:実際には型パラメーター Tが必要なため、例を単純化しすぎました。

正直なところ、投稿した要点のどこにあなたがたどり着くの、正直なところわかりません。TypeTag[T]コードを見ると、TypeTagパラメーター名を抽出するためにのみを使用しているようです。apply問題は、関数オブジェクトのメソッドのパラメーター名を実際に取得していることです。言い換えるv1v2Function2関数オブジェクトが異なるパラメーター名でメソッドをラップします。

とはいえ、これからTypeTagは関数型の を取得する必要があると仮定します。上記の最初の解決策 (パラメーターをまったく使用しない解決策) には実際には問題がないTため、もう一度試してみてください。図:

def foo[P1](f: P1 => Unit)(implicit tag: TypeTag[P1 => Unit], p1: Manifest[P1]) { println( "TypeTag: " + tag ) }
def foo[P1, P2](f: (P1, P2) => Unit)(implicit tag: TypeTag[(P1, P2) => Unit], p1: Manifest[P1], p2: Manifest[P2]) { println( "TypeTag: " + tag ) }
foo(theFunc _)

結果:

TypeTag: TypeTag[Int => Unit]

私には問題ないようです。したがって、それを使用することをお勧めします。

存在論では、これはまったくコンパイルされないことに注意してください(そのため、どこで を取得できたのかわかりませんAny):

def foo[P1](f: T forSome { type T <: (P1) => Unit})(implicit tag: TypeTag[T],  p1: Manifest[P1]) {}
def foo[P1, P2](f: T forSome { type T <: (P1, P2) => Unit})(implicit tag: TypeTag[T],  p1: Manifest[P1], p2: Manifest[P2]) {}

<console>:15: error: not found: type T
          def foo[P1, P2](f: T forSome { type T <: (P1, P2) => Unit})(implicit tag: TypeTag[T],  p1: Manifest[P1], p2: Manifest[P2]) {}
                                                                                            ^
<console>:14: error: not found: type T
          def foo[P1](f: T forSome { type T <: (P1) => Unit})(implicit tag: TypeTag[T],  p1: Manifest[P1]) {}
于 2013-02-04T00:16:28.423 に答える