简体   繁体   English

模式匹配失去了类型界限?

[英]Pattern matching loses type bounds?

Why isn't effects an Effect[A] ?为什么effects不是Effect[A] The types should line up from foo .类型应该从foo排列。

http://scastie.org/20029 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
    }

  }
}

I don't have an answer per say, but here are some thoughts.我没有每个人的答案,但这里有一些想法。 First of all, I've simplified and clarified your code example to minimize down to the problem:首先,我已经简化并澄清了您的代码示例,以尽量减少问题:

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
    }
  }
}

Let's note the error message we get for that line:让我们注意我们为该行获得的错误消息:

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

It's kind of strange the compiler decides that effect has type Effect[Any] .编译器决定effect类型是Effect[Any]有点奇怪。 But let's see what happens if we replace this definition:但是让我们看看如果我们替换这个定义会发生什么:

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

with this:有了这个:

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

Now we get a different error message:现在我们得到不同的错误信息:

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.

In this case, the types really don't match up right.在这种情况下,类型确实不匹配。 Let's walk through it.让我们来看看吧。 We know from outside the case statement that we have an ActionResult[M, A] .我们从case语句之外知道我们有一个ActionResult[M, A] But because of the covariance on the type param A , that ActionResult[M, A] may well be an ActionResult[M, B] forSome { type B <: A } .但是由于类型参数A的协方差, ActionResult[M, A]很可能是ActionResult[M, B] forSome { type B <: A } In other words, there may be some type B that is a sub-type of A , and foo[M, A] might return an ActionResult[M, B] .换句话说,可能存在某种类型BA的子类型,并且foo[M, A]可能返回ActionResult[M, B] In which case, effect would be an Effect[B] , and because the type parameter for Effect is invariant, this type is not compatible with Effect[A] .在这种情况下, effect将是Effect[B] ,并且因为Effect的类型参数是不变的,所以这种类型与Effect[A]不兼容。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM