1

次のコードFooが不変の場合は機能するのに、共変の場合は機能しないのはなぜですか? の共変バージョンは、 の呼び出しで引数に型がありますが必須Fooであるという型エラーを生成します。に対しても同様のエラーが生成されます。useF1Foo[T]F1useF2

分散注釈が から削除されたFoo場合、コードは機能します。に対するパターン マッチF1は、 という事実を明らかにするT = Intので、それxは型を持っていFoo[Int]ます。の引数でに変換するFoo[Int]ために、暗黙の変換関数が使用されます。についても同様です。Foo が共変である場合、このプロセスのどの部分が異なりますか? また、その理由は?F1useF1F2

// A GADT with two constructors
sealed abstract class Foo[+T]
final case class F1() extends Foo[Int]
final case class F2() extends Foo[Unit]

object Example {
  // A Foo[Int] can only be an F1
  implicit def refineGADT(x : Foo[Int]) : F1 = x.asInstanceOf[F1]
  // A Foo[Unit] can only be an F2
  implicit def refineGADT(x : Foo[Unit]) : F2 = x.asInstanceOf[F2]

  def useF1(x : F1) = ()
  def useF2(x : F2) = ()

  def demo[T](x : Foo[T]) = x match {
    case F1() => useF1(x) // error
    case F2() => useF2(x) // error
  }
}

一般に、GADT はサブタイプをより複雑にしますが、この場合、考えられる具象型はFoo[Int]との 2 つだけでありFoo[Unit]、それらの間にサブタイプの関係は成り立たないため、サブタイプはこの例に影響を与えるべきではありません。

4

2 に答える 2

0

まず、例を単純化しましょう (型消去を無視すると仮定します):

class Foo[+T] 

def demo[T](x : Foo[T]) = x match {
  case _: Foo[Int] => x: Foo[Int] //error but works with `class Foo[T]`
  case _: Foo[Unit] => x: Foo[Unit] //error but works with `class Foo[T]`
}

あるいは:

class Foo[T]
scala> def demo[T](x : Foo[T]) = x match {case _: Foo[Int] => x}
demo: [T](x: Foo[T])Foo[Int] //notice Int

class Foo[+T]
scala> def demo[T](x : Foo[T]) = x match {case _: Foo[Int] => x}
demo: [T](x: Foo[T])Foo[T] //notice T

xas 式の予想される型は、 Foo[_ >: T](戻り値の型に共分散が適用された結果としての) 存在型、またはより正確にはFoo[X >: T] forSome{type X}です。Foo[Int]したがって、コンパイラは、この機能またはバグ (マッチングのコンテキストでの型キャスト) が常に に属してRいることを証明できないため、存在する型に対しては機能しないため、処理できませR :> Foo[X]X >: Int。So Rmay :> Foo[Int]or may be :> Foo[Any]or something else :> Foo[_ :> Int]R可能な範囲の副産物を作成します。そのような副産物は にキャストできませんFoo[Int]:

class Foo[T] 

def demo(x : Foo[_]) = x match {
  case _: Foo[Int] => x: Foo[Int] //error
  case _: Foo[Unit] => x: Foo[Unit] //error 
}                 

<console>:9: error: type mismatch;
 found   : Foo[_$1] where type _$1
 required: Foo[Int]
             case a: Foo[Int] => x: Foo[Int] //error
                                 ^
                        ^

<console>:10: error: type mismatch;
 found   : Foo[_$1] where type _$1
 required: Foo[Unit]
             case a: Foo[Unit] => x: Foo[Unit] //error
                                  ^

PS共分散が存在性にどのように関連するかについての例:

scala> class Foo[T]
defined class Foo

scala> def demo[T](x : Foo[T]) = (x: Foo[_ >: Int]) //can't cast to something in Int..Any range
<console>:17: error: type mismatch;
 found   : Foo[T]
 required: Foo[_ >: Int]
Note: T <: Any, but class Foo is invariant in type T.
You may wish to define T as +T instead. (SLS 4.5)
       def demo[T](x : Foo[T]) = (x: Foo[_ >: Int])
                                  ^

scala> class Foo[+T]
defined class Foo

scala> def demo[T](x : Foo[T]) = (x: Foo[_ >: Int])
demo: [T](x: Foo[T])Foo[Any]
于 2015-04-03T06:00:41.843 に答える