包含するクラスとは対照的に、型パラメータが囲む方法から来ているのに、なぜパターンマッチング作業は異なっていますか?例えば、
trait Base[T]
case class Derived(v: Int) extends Base[Int]
class Test[A] {
def method(arg: Base[A]) = {
arg match {
case Derived(_) => 42
}
}
}
エラーになります
constructor cannot be instantiated to expected type;
found : A$A87.this.Derived
required: A$A87.this.Base[A]
case Derived(_) => 42
^
それが正常にコンパイルしながら、時にA
メソッドの型パラメータであり、
class Test {
def method[A](arg: Base[A]) = {
arg match {
case Derived(_) => 42
}
}
}
私は100%完全な答えを持っていないが、私はあなたのために十分であるかもしれないポインタを持っています。
非常に特定の方法でGADTs(一般代数的データ型)とScalaのコンパイラを扱っています。いくつかの例は、特殊な処理で解決されている、いくつかのケースが未解決です。義母は、穴の大半を埋めるためにしようとしている、そしてそれは、すでにしている解決しかし、まだかなりの数があり、関連する問題の多くを開いているものと同様。
Scalaの2コンパイラで扱う特別GADTの典型的な例は非常にあなたのユースケースに関連しています。我々は見てみる場合:
def method[A](arg: Base[A]) = {
arg match {
case Derived(_) => 42
}
}
そして我々は、明示的であることを戻り値の型を宣言しますA
:
def method[A](arg: Base[A]): A
それだけで罰金をコンパイルします。あなたのIDEには文句を言うかもしれませんが、コンパイラはそれを経由させます。この方法は、それを返すと言うA
、しかしにパターンマッチングケース評価しInt
、理論的にはコンパイルしないはずです。で、その特定のパターンマッチング分岐があるためしかし、コンパイラでGADTsの特別な処理は、それの罰金を言うA
ように「固定」されていますInt
(私たちは上の一致したためDerived
ですBase[Int]
)。
(私たちの場合はGADTのためのジェネリック型パラメータがA
)どこかで宣言する必要があります。そして、ここに興味深い部分です-取扱特別なコンパイラそれが囲む方法のタイプパラメータとして宣言されています場合にのみ動作します。それは型のメンバまたは囲むトレイト/クラスの型パラメータから来る場合は、自分自身を見られるように、それは、コンパイルされません。
私はそれが100%完全な答えではありませんと述べた理由はここにある-私はどの文書この適切に(例えば公式仕様など)具体的な場所を指すことはできません。ScalaでGADTsの取り扱い上のソースはに降りてくるカップル の ブログ記事によって素晴らしいです、が、あなたはより多くのそれよりたい場合は、コンパイラのコードを自分の中に掘る必要があります。私はまさにそれをやってみました、と私はそれがダウンしてくると思いますこの方法が、あなたは本当に深く行きたい場合は、あなたがより多くのScalaコンパイラのコードベースを経験したのping誰かにお勧めします。