请考虑以下代码段,这是我原始问题的简化版本:
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
}
当variable
需要RandomVariable[_0]
类型Assignment
时,Any
被推断为类型为value
的编译时错误。 为什么 _0
还没有推断出类型 case (variable: RandomVariable[T forSome {type T}]) :: tail =>
?我尝试按顺序为存在类型命名使用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)
给编译器一个提示,但也不会编译(说它找不到类型T,我也会对它的解释感兴趣)。
为了进一步激励,请考虑我们何时捕获类型参数:
value
此编译没有警告/错误。我可以在第一个例子中修改一些不需要这个额外功能的东西吗?
编辑:为了更明确,我想知道为什么_0
未被推断为variable
类型,即使_0
的类型为List[_0]
{1}}并且每个值都来自variable
中的{{1}}。另外我想知道是否还有其他方法可以告诉编译器这个事实(除了在上面给出的函数中捕获类型)。
答案 0 :(得分:1)
另一种编译解决方案,比使用函数捕获类型更清晰(?)。然而,在原始案例中,为什么类型推断失败更令人费解。
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
生成所需的结果,而不会出现匹配错误。
答案 1 :(得分:0)
你不应该将RandomVariable和Assignment的类型绑在一起吗?
def [A] enumerateAll(vars: List[RandomVariable[A]], evidence: List[Assignment[A]]): Double =
实际上,你可以更宽容,只是说
def [A] enumerateAll(vars: List[RandomVariable[A]], evidence: List[Assignment[_ <: A]]): Double =
答案 2 :(得分:0)
错误代码给出了解决方案的一些指示。
<console>:15: error: type mismatch;
found : RandomVariable[_0] where type _0
required: RandomVariable[Any]
Note: _0 <: Any, but class RandomVariable is invariant in type A.
You may wish to define A as +A instead. (SLS 4.5)
extendedEvidence = evidence :+ Assignment(variable, value)
它告诉你它看到了比推断更具体的类型,甚至建议使RandomVariable允许协变A.这将允许它在需要时向下改变类型。
case class RandomVariable[+A](values: List[A])
或者,您可以在enumerateAll中为两个参数显式设置泛型类型。以这种方式,它可以推断出合适的类型,而不是被迫推断任何。该定义不需要RandomVariable协变变化,因为两个参数属于同一类型。
def enumerateAll[A](vars: List[RandomVariable[A]], evidence: List[Assignment[A]]): Double =
这个问题可能有助于解释。 Why doesn't the example compile, aka how does (co-, contra-, and in-) variance work?