【问题标题】:Type inference and pattern maching in ScalaScala 中的类型推断和模式匹配
【发布时间】:2015-07-15 15:38:32
【问题描述】:

这不输入:

sealed trait BinOp[-InA, -InB, +Out]
case object Add extends BinOp[Int, Int, Int]

sealed trait Expression[+A]
final case class IntegerAtom(value: Int) extends Expression[Int]
final case class BinaryExp[-A, -B, +C](op: BinOp[A, B, C], lhs: Expression[A], rhs: Expression[B]) extends Expression[C]

def optimizeStep[A](x: Expression[A]): Expression[A] = x match {
  case BinaryExp(Add, IntegerAtom(a), IntegerAtom(b)) => IntegerAtom(a + b)
}

最直接的就是在模式匹配中使用case对象:

[error] (...) pattern type is incompatible with expected type;
[error]  found   : minimumexample.Add.type
[error]  required: minimumexample.BinOp[Any,Any,A]

看来这个可以通过引入眼出血来解决:

val AddOp = Add

然后:

case BinaryExp(AddOp, IntegerAtom(a), IntegerAtom(b)) => IntegerAtom(a + b)

然后:

[error] (...) type mismatch;
[error]  found   : minimumexample.IntegerAtom
[error]  required: minimumexample.Expression[A]
[error]     case BinaryExp(AddOp, IntegerAtom(a), IntegerAtom(b)) => IntegerAtom(a + b)
[error]                                                                         ^

我想尽可能安全地解决这个问题,而不是求助于.asInstanceOf[]。想法?

【问题讨论】:

  • 这是一个最小(非)工作示例。编译器不理解A在模式匹配后变成Int
  • 我的意思是,我在将代码粘贴到 REPL 时遇到的错误与您遇到的错误有很大不同。方差错误导致您询问的后续错误。

标签: scala pattern-matching type-inference


【解决方案1】:

您的代码的主要问题是BinaryExp 定义中的差异问题,但这似乎不在问题的范围内。固定方差后,您将面临case object 没有引入新类型的唯一不便。

解决此问题的典型模式是声明sealed trait,然后使用case object 对其进行扩展。

这是一个编译的例子

sealed trait BinOp[-InA, -InB, +Out]
sealed trait Add extends BinOp[Int, Int, Int]
case object Add extends Add

sealed trait Expression[+A]
final case class IntegerAtom(value: Int) extends Expression[Int]
final case class BinaryExp[A, B, C](op: BinOp[A, B, C], lhs: Expression[A], rhs: Expression[B]) extends Expression[C]

def optimizeStep[A](x: Expression[A]): Expression[A] = x match {
  case BinaryExp((_: Add), IntegerAtom(a), IntegerAtom(b)) => IntegerAtom(a + b)
}

地点:

  • 以一种简单的方式“修复”了差异(删除它)
  • 由于sealed trait 定义,Add 现在是一个类型
  • 匹配是用(_: Add)进行的

【讨论】:

  • 如果它只是一个案例对象,我认为您不需要(_: Add)。无论如何,它可以在我的版本中编译。
  • case object 确实引入了一种新类型;可以通过Add.type参考。
猜你喜欢
  • 2012-09-02
  • 2021-08-24
  • 1970-01-01
  • 1970-01-01
  • 2015-12-31
  • 1970-01-01
  • 2020-08-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多