问题描述
这个问题出现在我正在编写的模块中,但我做了一个表现出相同行为的最小案例.
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
之前确定 X
、S[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
类型变量T
和X
现在可以独立求解(因为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.
这篇关于为什么类型推断在这里不起作用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!