这是previous question I asked的后续行动,远未完成。随后的所有代码都在Scala控制台中编译并运行良好。
考虑以下抽象数据类型,以及作为类型类必须支持的操作:
trait SIG {
type XOrY
type X <: XOrY
type Y <: XOrY
}
trait SIGOps[Sig <: SIG] {
def makeX(s: String): Sig#X
def makeY(i: Int): Sig#Y
// the disjunction is enforced with that fold
def fold[T](xy: Sig#XOrY)(isX: String => T, isY: Int => T): T
// the following is for convenience, as we want to mimick case classes
object X {
def apply(s: String): Sig#X = makeX(s)
def unapply(xy: Sig#XOrY): Option[String] = fold(xy)(s => Some(s), i => None)
}
object Y {
def apply(i: Int): Sig#Y = makeY(i)
def unapply(xy: Sig#XOrY): Option[Int] = fold(xy)(s => None, i => Some(i))
}
}
现在,这是签名的可能实现。类型类实例位于伴随对象中以便于发现。
trait EitherSig extends SIG {
type XOrY = scala.util.Either[String, Int]
type X = scala.util.Left[String, Int]
type Y = scala.util.Right[String, Int]
}
object EitherSig {
implicit object EitherSIGOps extends SIGOps[EitherSig] {
def makeX(s: String): EitherSig#X = scala.util.Left[String, Int](s)
def makeY(i: Int): EitherSig#Y = scala.util.Right[String, Int](i)
def fold[T](xy: EitherSig#XOrY)(isX: String => T, isY: Int => T): T = xy match {
case Left(s) => isX(s)
case Right(s) => isY(s)
}
}
}
最后,这里是人们如何编写依赖于抽象签名的代码。
class Example[Sig <: SIG](implicit ops: SIGOps[Sig]) {
import ops._
def main(args: Array[String]): Unit = {
val xy: Sig#XOrY = X("foo")
xy match {
case X(s) => println("X: "+s)
// Scala does not see that the pattern matching is not exhaustive if when I comment the following line
// case Y(i) => println("Y: "+i)
}
}
}
object ConcreteExample extends Example[EitherSig]
它按预期工作:
scala> ConcreteExample.main(Array())
X: foo
问题如下:我如何教Scala识别模式匹配何时不像上述那样详尽?
可能有a way to communicate this information to the typechecker,但我不知道如何。
答案 0 :(得分:0)
Jason Zaugg给了an answer on Twitter:
[...]我们没有扩展点。只考虑密封的层次结构。
Travis Brown proposed至Write a matchExhaustive macro that inspects the partial function
但不认为是Worth the trouble when you've got the fold
。
现在对这个问题没有真正的解决方案。