在这种情况下,scala的类型检查如何工作? [英] how does scala's type check work in this case?
问题描述
// Start writing your ScalaFiddle code here
sealed trait DSL[A]{
// def run(): A ={
// this match {
// case GetLength(something) =>
// something.length
// case ShowResult(number) =>
// s"the length is $number"
// }
// }
}
case class GetLength(something: String) extends DSL[Int]
case class ShowResult(number: Int) extends DSL[String]
def run[A](fa:DSL[A]): A ={
fa match {
case GetLength(something) =>
something.length
case ShowResult(number) =>
s"the length is $number"
}
}
val dslGetLength = GetLength("123456789")
val length = run(dslGetLength)
val dslShowResult = ShowResult(length)
println(run(dslShowResult))
// print: the length is 9
- 为什么
run
函数不能在DSL [A]
特性中编译,但可以在外部工作? - 在这种情况下,类型推断如何工作?
- why does the
run
function not compile in theDSL[A]
trait, but worked outside? - how does type inference work in this case?
推荐答案
这是广义抽象数据类型的情况.
This is a case of generalized abstract data type.
当您有 DSL [A]
且函数返回 A
时,编译器可以证明:
When you have a DSL[A]
and function returning A
, compiler can prove that:
- 用于
case GetLength
A = Int
,因此您可以在那里返回Int
- 用于
case ShowResult
A = String
,因此您可以返回String
- for
case GetLength
A=Int
so you can returnInt
there - for
case ShowResult
A=String
so you can returnString
但是,众所周知,Scala 2没有对GADT的完美支持,因此有时编译器即使可以工作也会失败.我猜有些编译器开发人员可以弄清楚确切的情况,但是有趣的是,它可以解决:
however, Scala 2 is known to not have a perfect support of GADTs, so sometimes compiler fails, even if it should work. I guess some compiler dev could figure out the exact case, but, interestingly, it can be worked around with:
sealed trait DSL[A]{
def run(): A = DSL.run(this)
}
object DSL {
def run[A](fa:DSL[A]): A ={
fa match {
case GetLength(something) =>
something.length
case ShowResult(number) =>
s"the length is $number"
}
}
}
case class GetLength(something: String) extends DSL[Int]
case class ShowResult(number: Int) extends DSL[String]
我的疯狂猜测是,通用方法中的模式匹配在编译器中是一种特殊情况,当 A
固定时不会触发.我认为是这样,因为以下代码也可以工作:
My wild guess would be that pattern matching in a generic method is kind of a special case in a compiler, which is not triggered when A
is fixed. I think that, because the following code also works:
sealed trait DSL[A]{
def run(): A = runMe(this)
private def runMe[B](dsl: DSL[B]): B = {
dsl match {
case GetLength(something) =>
something.length
case ShowResult(number) =>
s"the length is $number"
}
}
}
这同样会失败:
sealed trait DSL[A]{
def run(): A = {
val fa: DSL[A] = this // make sure error is not related to special treatment of "this", this.type, etc
fa match {
case GetLength(something) =>
something.length
case ShowResult(number) =>
s"the length is $number"
}
}
}
cmd4.sc:5: constructor cannot be instantiated to expected type;
found : ammonite.$sess.cmd4.GetLength
required: ammonite.$sess.cmd4.DSL[A]
case GetLength(something) =>
^
cmd4.sc:7: constructor cannot be instantiated to expected type;
found : ammonite.$sess.cmd4.ShowResult
required: ammonite.$sess.cmd4.DSL[A]
case ShowResult(number) =>
^
Compilation Failed
换句话说,我怀疑类型参数会改变事物的评估方式:
In other words, I suspect that type parameter change how things are being evaluated:
-
def runMe [B](dsl:DSL [B]):B
具有类型参数,因此match
case 的结果>与B
进行比较,在每种情况下,可以证明B
的值是某种特定类型(Int,String) - 在
def run:A
中,但是以某种方式阻止了编译器进行这种分析-恕我直言,这是一个bug,但这也许是某些晦涩功能的结果.
def runMe[B](dsl: DSL[B]): B
has a type parameter, so results of eachcase
insidematch
are compared againstB
where for each case value ofB
can be proven to be some specific type (Int, String)- in
def run: A
however compiler is somehow prevented from making such analysis - IMHO it is a bug, but perhaps it is a result of some obscure feature.
从我看到的相同错误中发现了Dotty,所以它要么是重复的错误,要么是类型级别检查器的限制(毕竟,所有GADT尚未广泛使用din Scala)-我建议将问题报告给Scala/Dotty团队让他们决定是什么.
From what I see the same error occurs in Dotty, so it is either duplicated bug or a limitation of a type-level checker (after all GADT aren't widely use din Scala, yet) - I would suggest reporting issue to Scala/Dotty team and letting them decide what it is.
这篇关于在这种情况下,scala的类型检查如何工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!