【问题标题】:Why doesn't type inference work here?为什么类型推断在这里不起作用?
【发布时间】:2012-04-27 00:34:05
【问题描述】:

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

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_| 来简化这件事。

实际错误:

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

【问题讨论】:

    标签: scala structural-typing type-bounds


    【解决方案1】:

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

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

    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 现在可以独立求解(因为X 的绑定中不再提及T)。这意味着X 立即被推断为Minimal,并且T 被求解为隐式搜索X =&gt; S[T] 类型值以满足隐式参数conv 的一部分。 conformsscala.Predef 中制造这种形式的值,并且在上下文中将保证给定Minimal 类型的参数,T 将被推断为 Int。您可以将其视为在 Scala 中工作的 functional dependencies 的一个实例。

    【讨论】:

    • 是的,这个解决方案在我的情况下运行良好。它也比 Joshua 的解决方案更清洁(对不起 Joshua!)。那么,您能解释一下为什么 Joshua 的解决方案有效吗?
    • 答案已更新,以解释为什么 Joshua 的解决方案也有效。
    【解决方案2】:

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

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

    【讨论】:

    • 很好,这行得通,但是这些方法之间肯定没有区别吗?在这种情况下查看视图只是转换为超类,不是吗?这是否意味着此修复只是针对编译器中的错误的一种解决方法?
    • 啊,现在我明白了,S 不是超类——它只是一个视图(在某种意义上)。因此,尽管在大多数情况下不需要视图绑定,但视图绑定更合适。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-03-19
    • 2017-06-22
    • 1970-01-01
    • 1970-01-01
    • 2013-05-29
    • 1970-01-01
    • 2012-01-15
    相关资源
    最近更新 更多