神秘的GADT skolem:什么类型试图逃避其范围?

时间:2016-03-15 04:10:12

标签: scala recursion type-inference gadt

Scala 11.2给了我这个错误:

error: type mismatch;
 found   : Seq[Some[V]]
 required: Seq[Option[?V8]] where type ?V8 <: V (this is a GADT skolem)
            val output = f(ivs.map(iv => Some(iv.get._1)))
                                   ^

首先,这似乎是一个奇怪的错误信息:Seq [Some [V]]是否符合Seq [Option [V]]?

以下是周围代码的相似部分:

  def evalDependencyTree[V]
    (linkRelevance: LinkInfo => Option[LinkStrength])
    (dtree: DependencyTree[V, LinkInfo], strengthSoFar: LinkStrength = 1.0)
  : Option[(V, LinkStrength)] = dtree match {
    . . .
    case DFunction(f, inputs) => {
      val ivs = inputs.map { input =>
        evalDependencyTree(linkRelevance)(input, strengthSoFar) // <-- Recursive call
      }
      val output = f(ivs.map(iv => Some(iv.get._1))) // <-- The line with the error
      . . .
    }
  }

  trait DependencyTree[+V, +L]

  case class DFunction[V, L](
    f: Seq[Option[V]] => Option[V], inputs: Seq[DependencyTree[V, L]])
    extends DependencyTree[V, L]

我(非常有限)对GADT skolems的理解是它们是类型推断期间编译器定义的类型,它复制现有的类型参数以防止该类型“转义”其作用域,如在递归调用中 - 也就是说,防止从无法访问该类型的更广泛的范围引用它。

我不知道V如何在不同范围内引用不​​同类型。对evalDependencyTree的递归调用与V的当前调用具有相同的类型参数evalDependencyTree。我尝试为递归调用显式编写evalDependencyTree[V],但编译器返回了相同的错误消息。当evalDependencyTree没有类型参数时,此代码确实有效;在该版本中,dtree被硬编码为DependencyTree[Int, LinkInfo]

什么类型试图逃脱?或者说,我做错了什么?

1 个答案:

答案 0 :(得分:1)

我自己找到了一个解决方法:明确地在模式匹配中拼出完整类型的f,如下所示:

case DFunction(f: Seq[Option[V]] => Option[V], inputs) => . . .

这有效,但我不接受它作为答案,因为我没有解释为什么它是必要的。我仍然不知道何时会发生这种错误或导致错误的原因。如果你知道,请发一个答案!

另外,我原本认为明确为f提供的大部分类型都会因类型擦除而丢失。因此,我有两件重要的事情可以解释这个变通方法。