为什么不在这里输入推理?

时间:2012-04-27 00:34:05

标签: scala structural-typing type-bounds

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

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
}

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

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

更多信息:此代码是尝试语法糖的简单示例。原始代码尝试使|(a)|表示a的模数,其中a是向量。显然|(a)|比写|[Float,Vector3[Float]](a)|更好,但遗憾的是我不能使用unary_|来简化这一过程。

实际错误:

  

推断类型参数[Nothing,Minimal [Int]]不符合方法apply的类型参数bounds [T,X&lt;:Sugar.S [T]]

2 个答案:

答案 0 :(得分:9)

这不是Scala编译器错误,但它肯定是Scala类型推断的限制。在解决X之前,编译器想要确定S[T]X上的绑定,但是绑定提到了迄今为​​止无约束的类型变量T,它因此修复了Nothing {1}}从那里开始。一旦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

desugars to,

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

现在可以独立解决类型变量TX(因为T的约束中不再提及X。这意味着X立即被推断为Minimal,并且T作为隐式搜索类型X => S[T]的值的一部分来解决,以满足隐式参数{ {1}}。 conv中的conforms生成此表单的值,并且在上下文中将保证给定类型scala.Predef的参数,Minimal将被推断为Int。您可以在Scala中将其视为functional dependencies的实例。

答案 1 :(得分:4)

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

def apply[T, X <% S[T]] (x: X) = x.doSomething效果很好。