了解Scala GADT支持的限制
Test.test中的错误似乎是不合理的:
sealed trait A[-K,+V] case class B[+V]() extends A[Option[Unit],V] case class Test[U]() { def test[V](t: A[Option[U],V]) = t match { case B() => null // constructor cannot be instantiated to expected type; found : B[V] required: A[Option[U],?V1] where type ?V1 <: V (this is a GADT skolem) } def test2[V](t: A[Option[U],V]) = Test2.test2(t) } object Test2 { def test2[U,V](t: A[Option[U],V]) = t match { case B() => null // This works } } 有几种方法可以使错误更改或消失: 如果我们删除trait A(和case B类)上的V参数,错误的“GADT-Skolem”部分就会消失,但是“构造函数不能被实例化”的部分仍然存在. 如果我们将Test类的U参数移动到Test.test方法,则该错误消失.为什么(类似地,Test2.test2中不存在该错误) 以下链接也标识出这个问题,但我不明白提供的解释. http://lambdalog.seanseefried.com/tags/GADTs.html 这是编译器中的错误吗? (2.10.2-RC2) 感谢您的任何帮助澄清. 2014/08/05:我已经设法进一步简化代码,并提供另一个例子,其中U绑定在即时函数之外,而不会导致编译错误.我仍然在2.11.2中看到这个错误. sealed trait A[U] case class B() extends A[Unit] case class Test[U]() { def test(t: A[U]) = t match { case B() => ??? // constructor cannot be instantiated to expected type; found : B required: A[U] } } object Test2 { def test2[U](t: A[U]) = t match { case B() => ??? // This works } def test3[U] = { def test(t: A[U]) = t match { case B() => ??? // This works } } } 像这样简化,这看起来更像编译器的bug或限制.还是我错过了什么? 解决方法
构造函数模式必须符合模式的预期类型,这意味着B <:A [U],如果U是当前正在调用的方法的类型参数,则为真(因为可以将其实例化为适当类型参数),但如果U是先前绑定的类类型参数,则不真实. 你当然可以质疑“必须符合”规则的价值.我知道我有我们通常通过上传监护程序来避免这个错误,直到构造函数模式符合.特别,
// Instead of this def test1(t: A[U]) = t match { case B() => ??? } // Write this def test2(t: A[U]) = (t: A[_]) match { case B() => ??? } 附录:在评论中,提问者说:“问题很简单,为什么它不适用于类级别的类型参数,但在方法级别工作.实例化类类型参数在外部可见,并且具有无限期的生命周期,对于实例化的方法类型参数都不是这样.这对类型健全有影响.给予Foo [A],一旦我拥有一个Foo [Int],那么当指向该实例时,A必须是Int,永远和永远. 原则上,您可以在构造函数调用中类似地处理类类型参数,因为type参数仍然是未绑定的,并且可以机会地推断.就是这样.一旦出现在世界各地,就没有重新谈判的余地. 另外一个补充:我看到人们做了很多工作,把编译器作为正确性的一个前提,我们所需要做的只是思考它的输出,直到我们的理解发展到足以匹配它为止.这样的精神体操已经在那个帐篷下发生了,我们可以帮助太阳马戏团过几次. scala> case class Foo[A](f: A => A) defined class Foo scala> def fail(foo: Any,x: Any) = foo match { case Foo(f) => f(x) } fail: (foo: Any,x: Any)Any scala> fail(Foo[String](x => x),5) java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String at $anonfun$1.apply(<console>:15) at .fail(<console>:13) ... 33 elided 这是scala的当前版本 – 这仍然是它所做的.没有警告.所以也许问自己,在十多年的生存之后,提出对一种语言和实施的正确性推定是非常明智的. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |