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

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)的内部参数,但随后将另一次出现的T设置为Nothing,这显然与apply不匹配。这些绝对是T,因为删除第一个参数会使第二个提示说T未定义。

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

进一步的信息:该代码是尝试语法糖的简单示例。原始代码尝试使|(a)|表示a的模数,其中a是一个向量。显然,|(a)|比编写|[Float,Vector3[Float]](a)|更好,但是不幸的是,我无法使用unary_|来简化此操作。

实际错误:

最佳答案

这不是Scala编译器的错误,但肯定是Scala类型推断的局限性。编译器希望在求解X之前确定S[T]X的界限,但是界限提到了迄今为​​止不受约束的类型变量T,因此它固定在Nothing并从那里开始。一旦T已完全解决,它就不会重新访问X…目前,在这种情况下,类型推断总是从左向右进行。

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

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

在这里,将推断T,以便Minimal直接符合S[T]而不是通过中介的有界类型变量。

更新

Joshua的解决方案还避免了推断类型T的问题,但采用了完全不同的方式。
def apply[T, X <% S[T]](x : X) = x.doSomething

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

现在可以独立地解决类型变量TX的问题(因为T的绑定(bind)中不再提到X)。这意味着X立即被推断为Minimal,并且T作为隐式搜索的一部分来求解X => S[T]类型的值,以满足隐式参数convconforms中的scala.Predef会制造这种形式的值,并且在上下文中将保证给定Minimal类型的参数时,T将被推断为Int。您可以在Scala中将其视为functional dependencies的实例。

关于scala - 为什么输入推断在这里不起作用?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/10343244/

10-11 11:23