存在类型的Scala类型推断 [英] Scala type inference on an existential type
问题描述
考虑以下代码片段,这是我原来的问题的简化版本:
Consider the following code snippet, which is a reduced version of my original problem:
case class RandomVariable[A](values: List[A])
case class Assignment[A](variable: RandomVariable[A], value: A)
def enumerateAll(vars: List[RandomVariable[_]], evidence: List[Assignment[_]]): Double =
vars match {
case variable :: tail =>
val enumerated = for {value <- variable.values
extendedEvidence = evidence :+ Assignment(variable, value)
} yield enumerateAll(tail, extendedEvidence)
enumerated.sum
case Nil => 1.0
}
此操作失败,并出现编译时错误,当Assignment
要求类型为Any
时,推断出variable
具有类型RandomVariable[_0]
. 为什么 value
还不能推断出其类型 _0
?通过使用case (variable: RandomVariable[T forSome {type T}]) :: tail =>
到编译器,但也不会编译(说它找不到类型T,我也想对它进行解释).
This fails with the compile-time error that variable
was inferred to have type RandomVariable[_0]
when Assignment
required type Any
. Why is value
not also inferred to have type _0
? I tried giving the existential type a name in order to give a hint to the compiler by using case (variable: RandomVariable[T forSome {type T}]) :: tail =>
but that also would not compile (saying it could not find type T, which I'd be interested in an explanation for as well).
为了获得进一步的动力,请考虑何时捕获类型参数,如下所示:
For further motivation, consider when we capture the type parameter as follows:
case variable :: tail =>
def sum[A](variable: RandomVariable[A]): Double = {
val enumerated = for {value <- variable.values
extendedEvidence = evidence :+ Assignment(variable, value)
} yield enumerateAll(tail, extendedEvidence)
enumerated.sum
}
sum(variable)
此编译没有警告/错误.我可以在第一个示例中进行一些修改,以使其不需要此额外功能吗?
This compiles without warnings/errors. Is there something I can modify in the first example to not require this extra function?
编辑:更明确地说,我想知道为什么即使variable
的类型为_0
且每个值都不能将value
推断为_0
类型来自variable
中的List[_0]
.我也想知道是否还有其他方法可以告诉编译器这个事实(除了如上所述捕获函数中的类型之外).
EDIT: To be more explicit, I want to know why value
is not inferred to be of type _0
even though variable
is of type _0
and every value comes from a List[_0]
in variable
. Also I would like to know if there are any additional ways to tell the compiler of this fact (aside from capturing the type in a function as I gave above).
推荐答案
另一种编译解决方案,比使用函数捕获类型更清洁(?).但是,这使得在原始情况下类型推断失败的原因更加令人困惑.
Another compiling solution, that is cleaner(?) than using a function to capture the type. However, it makes it even more puzzling as to why type inference fails in the original case.
def enumerateAll(vars: List[RandomVariable[_]], evidence: List[SingleAssignment[_]]): Double = vars match {
case (variable@RandomVariable(values)) :: tail =>
val enumeration = for {value <- values
assignment = SingleAssignment(variable, value)
extendedEvidence = evidence :+ assignment
} yield enumerateAll(tail, extendedEvidence)
enumeration.sum
case Nil => 1.0
}
它还会返回以下警告:
scala: match may not be exhaustive.
It would fail on the following input: List((x: questions.RandomVariable[?] forSome x not in questions.RandomVariable[?]))
def enumerateAll(vars: List[RandomVariable[_]], evidence: List[SingleAssignment[_]]): Double = vars match {
截至该帖子我仍无法解读.同样,使用一些测试用例运行它会产生期望的结果,而在参数列表中使用int,double和string的RandomVariable
不会产生匹配错误.
Which I'm unable to decipher as of this posting. Also, running it with a few test cases produces the desired result without a match error using RandomVariable
s of int, double, and string in the parameter list.
这篇关于存在类型的Scala类型推断的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!