我正在尝试使用依赖方法类型和编译器的每晚构建(2.10.0.r26005-b20111114020239)来抽象模块中的case类。我从Miles Sabin' example找到了一些灵感。
我真的不明白下面(自包含)代码中的错误。输出取决于foo
中模式的顺序。
// afaik, the compiler doesn't not expose the unapply method
// for a companion object
trait Isomorphic[A, B] {
def apply(x: A): B
def unapply(x: B): Option[A]
}
// abstract module
trait Module {
// 3 types with some contraints
type X
type Y <: X
type Z <: X
// and their "companion" objects
def X: Isomorphic[Int, X]
def Y: Isomorphic[X, Y]
def Z: Isomorphic[Y, Z]
}
// an implementation relying on case classes
object ConcreteModule extends Module {
sealed trait X { val i: Int = 42 }
object X extends Isomorphic[Int, X] {
def apply(_s: Int): X = new X { }
def unapply(x: X): Option[Int] = Some(x.i)
}
case class Y(x: X) extends X
// I guess the compiler could do that for me
object Y extends Isomorphic[X, Y]
case class Z(y: Y) extends X
object Z extends Isomorphic[Y, Z]
}
object Main {
def foo(t: Module)(x: t.X): Unit = {
import t._
// the output depends on the order of the first 3 lines
// I'm not sure what's happening here...
x match {
// unchecked since it is eliminated by erasure
case Y(_y) => println("y "+_y)
// unchecked since it is eliminated by erasure
case Z(_z) => println("z "+_z)
// this one is fine
case X(_x) => println("x "+_x)
case xyz => println("xyz "+xyz)
}
}
def bar(t: Module): Unit = {
import t._
val x: X = X(42)
val y: Y = Y(x)
val z: Z = Z(y)
foo(t)(x)
foo(t)(y)
foo(t)(z)
}
def main(args: Array[String]) = {
// call bar with the concrete module
bar(ConcreteModule)
}
}
有什么想法吗?
答案 0 :(得分:1)
这些警告是正确的,也是可以预料到的,因为从foo
中查看Y
和Z
都会被删除到它们的边界,即。 X
。
更令人惊讶的是,针对Y
的匹配或针对Z
的匹配的存在阻碍了与X
的匹配,即。在这种情况下,
def foo(t: Module)(x: t.X): Unit = {
import t._
// the output depends on the order of the first 3 lines
// I'm not sure what's happening here...
x match {
// unchecked since it is eliminated by erasure
// case Y(_y) => println("y "+_y)
// unchecked since it is eliminated by erasure
// case Z(_z) => println("z "+_z)
// this one is fine
case X(_x) => println("x "+_x)
case xyz => println("xyz "+xyz)
}
}
结果是,
x 42
x 42
x 42
这似乎是合理的,而其中一个较早的比赛已恢复,
def foo(t: Module)(x: t.X): Unit = {
import t._
// the output depends on the order of the first 3 lines
// I'm not sure what's happening here...
x match {
// unchecked since it is eliminated by erasure
case Y(_y) => println("y "+_y)
// unchecked since it is eliminated by erasure
// case Z(_z) => println("z "+_z)
// this one is fine
case X(_x) => println("x "+_x)
case xyz => println("xyz "+xyz)
}
}
结果是,
xyz AbstractMatch$ConcreteModule$X$$anon$1@3b58fa97
y AbstractMatch$ConcreteModule$X$$anon$1@3b58fa97
xyz Z(Y(AbstractMatch$ConcreteModule$X$$anon$1@3b58fa97))
没有:我看不出有什么好的理由为什么额外的案例会导致xyz
超过X
,所以我认为你遇到了一个错误的模式匹配器。我建议您搜索Scala JIRA以查找类似问题,如果找不到,请打开一张带有从上面提取的最小化再现示例的票证。
老实说,在上面的第二个例子中,由于Y
被删除到Y
和{{{},我希望在所有三个实例中都选择X
个案。 1}}匹配表达式中Y
个案例之前的情况。但是我们在这里处于不受控制的领域,我对自己的直觉并不是100%自信。