2016-05-26 2 views
2

なぜeffectsEffect[A]ですか?タイプはfooになります。パターンマッチングはタイプ境界を失うか?

http://scastie.org/20029

/*** 
scalaVersion := "2.11.8" 

*/ 
trait Effect[A] 

sealed trait ActionResult[+M, +A] { 
} 

sealed trait ModelUpdated[+M] extends ActionResult[M, Nothing] { 
} 

sealed trait HasEffect[+M, +A] extends ActionResult[M, A] { 
} 

sealed trait UpdateSilent 

object ActionResult { 

    case object NoChange extends ActionResult[Nothing, Nothing] 

    final case class ModelUpdate[M](newModel: M) extends ModelUpdated[M] 

    final case class ModelUpdateSilent[M](newModel: M) extends ModelUpdated[M] with UpdateSilent 

    final case class EffectOnly[A](effect: Effect[A]) extends ActionResult[Nothing, A] with HasEffect[Nothing, A] 

    final case class ModelUpdateEffect[M, A](newModel: M, effect: Effect[A]) extends ModelUpdated[M] with HasEffect[M, A] 

    final case class ModelUpdateSilentEffect[M, A](newModel: M, effect: Effect[A]) 
    extends ModelUpdated[M] with HasEffect[M, A] with UpdateSilent 

    def apply[M, A](model: Option[M], effect: Option[Effect[A]]): ActionResult[M, A] = (model, effect) match { 
    case (Some(m), Some(e)) => ModelUpdateEffect(m, e) 
    case (Some(m), None) => ModelUpdate(m) 
    case (None, Some(e)) => EffectOnly(e) 
    case _     => NoChange 
    } 
} 

object Main { 
    def foo[A, B]: ActionResult[A, B] = ??? 
    def dispatch[A, B] = { 
    foo[A, B] match { 
     case ActionResult.NoChange => 
     false 
     case ActionResult.ModelUpdate(newModel) => 
     false 
     case ActionResult.ModelUpdateSilent(newModel) => 
     true 
     case ActionResult.EffectOnly(effects) => 
     true 
     case ActionResult.ModelUpdateEffect(newModel, effects) => 
     val e: Effect[A] = effects 
     false 
     case ActionResult.ModelUpdateSilentEffect(newModel, effects: Effect[A]) => 
     true 
    } 

    } 
} 
+0

あなたは 'val e:Effect [B] = effects'を意味しませんか? –

答えて

1

は、私が言うあたりの答えを持っていないが、ここでいくつかの考えがあります。まず第一に、私は単純化されてきたし、問題にまで最小化するためにあなたのコードの例を明らかに:

trait Effect[A] 
trait ActionResult[+M, +A] 
trait ModelUpdated[+M] extends ActionResult[M, Nothing] 
trait HasEffect[+M, +A] extends ActionResult[M, A] 

case class ModelUpdateEffect[M, A](newModel: M, effect: Effect[A]) extends ModelUpdated[M] with HasEffect[M, A] 

object Main { 
    def foo[M, A]: ActionResult[M, A] = ??? 
    def dispatch[M, A] = { 
    foo[M, A] match { 
     case ModelUpdateEffect(newModel, effect) => 
     val e: Effect[A] = effect // does not compile                
     false 
     case _ => true 
    } 
    } 
} 

のは、私たちはその行の取得エラーメッセージに注意しましょう:

type mismatch; 
found : Effect[Any] 
required: Effect[A] 
Note: Any >: A, but trait Effect is invariant in type A. 

それは一種の奇妙ですコンパイラはeffectがタイプEffect[Any]であると判断します。しかし、我々はこの定義を置き換えるとどうなるか見てみましょう:これで

case class ModelUpdateEffect[M, A](newModel: M, effect: Effect[A]) extends ModelUpdated[M] with HasEffect[M, A] 

:この場合

type mismatch; 
found : Effect[?A1] where type ?A1 <: A (this is a GADT skolem) 
required: Effect[A] 
Note: ?A1 <: A, but trait Effect is invariant in type A. 

、本当に種類:

case class ModelUpdateEffect[M, A](newModel: M, effect: Effect[A]) extends HasEffect[M, A] 

は、今、私たちは、さまざまなエラーメッセージが表示されます右上に一致しないでください。それを歩みましょう。我々はcaseの声明の外から、ActionResult[M, A]があることを知っています。しかし、型パラメータAの共分散のために、そのActionResult[M, A]ActionResult[M, B] forSome { type B <: A }である可能性があります。つまり、サブタイプがABがあり、foo[M, A]ActionResult[M, B]を返すことがあります。この場合、effectEffect[B]となり、Effectの型パラメータは不変であるため、この型はEffect[A]と互換性がありません。