6

这个问题出现在我正在编写的模块中,但我制作了一个表现相同行为的最小案例。

class Minimal[T](x : T) {
  def doSomething = x
}

object Sugar {
  type S[T] = { def doSomething : T }
  def apply[T, X <: S[T]] (x: X) = x.doSomething
}

object Error {
  val a = new Minimal(4)
  Sugar(a) // error: inferred [Nothing, Minimal[Int]] does not fit the bounds of apply
  Sugar[Int, Minimal[Int]](a) // works as expected
}

问题是编译器设法找出Minimal( Int) 的内部参数,但随后将另一个出现设置TNothing,这显然不匹配apply。这些绝对是相同的T,因为删除第一个参数会使第二个参数抱怨 T 未定义。

是否有一些歧义意味着编译器无法推断第一个参数,或者这是一个错误?我可以优雅地解决这个问题吗?

更多信息:此代码是尝试语法糖的简单示例。原始代码试图使|(a)|的模均值a,其中 a 是一个向量。显然|(a)|比写作好|[Float,Vector3[Float]](a)|,但不幸的是我不能用它unary_|来让这更容易。

实际错误:

推断的类型参数 [Nothing,Minimal[Int]] 不符合方法应用的类型参数边界 [T,X <: Sugar.S[T]]

4

2 回答 2

9

这不是 Scala 编译器错误,但它肯定是 Scala 类型推断的限制。编译器想在求解 , 之前确定 , 的边界X,但边界提到了迄今为​​止不受约束的类型变量,因此它固定在该变量上并从那里继续。一旦完全解决,它就不会重新访问......在这种情况下,当前类型推断总是从左到右进行。S[T]XTNothingTX

如果您的示例准确地代表了您的真实情况,那么有一个简单的解决方法,

def apply[T](x : S[T]) = x.doSomething

这里T将被推断Minimal为直接符合S[T]而不是通过中间有界类型变量。

更新

Joshua's solution also avoids the problem of inferring type T, but in a completely different way.

def apply[T, X <% S[T]](x : X) = x.doSomething

desugars to,

def apply[T, X](x : X)(implicit conv : X => S[T]) = x.doSomething

The type variables T and X can now be solved for independently (because T is no longer mentioned in X's bound). This means that X is inferred as Minimal immediately, and T is solved for as a part of the implicit search for a value of type X => S[T] to satisfy the implicit argument conv. conforms in scala.Predef manufactures values of this form, and in context will guarantee that given an argument of type Minimal, T will be inferred as Int. You could view this as an instance of functional dependencies at work in Scala.

于 2012-04-27T08:28:35.023 回答
4

结构类型的界限有些奇怪,请尝试使用 S[T] 上的视图界限。

def apply[T, X <% S[T]] (x: X) = x.doSomething工作正常。

于 2012-04-27T00:46:11.593 回答