本文介绍了为什么类型推断在这里不起作用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

class Minimal[T](x : T) {def doSomething = x}对象糖{类型 S[T] = { def doSomething : T }def apply[T, X 

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

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

更多信息:此代码是尝试使用语法糖的一个简单示例.原始代码试图使 |(a)| 表示 a 的模数,其中 a 是向量.很明显|(a)|比写|[Float,Vector3[Float]](a)|要好,但不幸的是我不能使用unary_| 使这更容易.

实际错误:

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

解决方案

这不是 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 

脱糖,

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

类型变量TX 现在可以独立求解(因为X 中不再提到T代码>的绑定).这意味着 X 立即被推断为 Minimal,并且 T 被解析为隐式搜索 X =>S[T] 满足隐式参数 conv.scala.Predef 中的 conforms 制造这种形式的值,并且在上下文中将保证给定类型为 Minimal, T 将被推断为 Int.您可以将此视为 函数依赖项在 Scala 中工作的一个实例.>

This problem arose in a module I'm writing, but I have made a minimal case that exhibits the same behaviour.

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
}

The problem is that the compiler manages to figure out the inner parameter for Minimal (Int), but then sets the other occurrence of T to Nothing, which obviously does not match apply. These are definitely the same T, as removing the first parameter makes the second complain that T is not defined.

Is there some ambiguity that means that the compiler cannot infer the first parameter, or is this a bug? Can I work around this gracefully?

Further information: This code is a simple example of an attempt at syntactic sugar. The original code tries to make |(a)| mean the modulus of a, where a is a vector. Clearly |(a)| is better than writing |[Float,Vector3[Float]](a)|, but unfortunately I can't use unary_| to make this easier.

The actual error:

解决方案

This isn't a Scala compiler bug, but it's certainly a limitation of Scala's type inference. The compiler wants to determine the bound on X, S[T], before solving for X, but the bound mentions the so far unconstrained type variable T which it therefore fixes at Nothing and proceeds from there. It doesn't revisit T once X has been fully resolved ... currently type inference always proceeds from left to right in this sort of case.

If your example accurately represents your real situation then there is a simple fix,

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

Here T will be inferred such that Minimal conforms to S[T] directly rather than via an intermediary bounded type variable.

Update

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.

这篇关于为什么类型推断在这里不起作用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-26 01:22