存在类型的Scala类型推断 [英] Scala type inference on an existential type

查看:100
本文介绍了存在类型的Scala类型推断的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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 RandomVariables of int, double, and string in the parameter list.

这篇关于存在类型的Scala类型推断的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆