3

考虑以下代码片段,它是我原来问题的简化版本:

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
  }

这会失败并出现编译时错误,该错误在required type时variable被推断为具有type 。为什么也不推断有类型我尝试为存在类型命名,以便通过使用向编译器提供提示,但这也不会编译(说它找不到类型 T,我也有兴趣对此进行解释)。RandomVariable[_0]AssignmentAny value _0case (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)

这编译没有警告/错误。我可以在第一个示例中修改某些内容以不需要此额外功能吗?

编辑:更明确地说,我想知道为什么value不被推断为类型_0,即使variable是类型_0并且每个值都来自List[_0]in variable。另外我想知道是否有任何其他方法可以告诉编译器这个事实(除了捕获我上面给出的函数中的类型)。

4

3 回答 3

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 {

截至发稿时,我无法破译。RandomVariable此外,使用参数列表中的 int、double 和 string 的 s 使用几个测试用例运行它会产生所需的结果,而不会出现匹配错误。

于 2013-01-10T06:03:40.850 回答
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 = 
于 2013-01-10T04:21:52.647 回答
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 = 

这个问题可能有助于解释。为什么示例不编译,也就是(co-,contra-和in-)方差如何工作?

于 2013-01-10T05:40:36.240 回答