为什么scala编译器不会使用抽象类型推断类型

时间:2014-10-09 21:41:26

标签: scala type-inference path-dependent-type

给出以下代码

trait A { type B }
case class C extends A { type B = String }
def f[V <: A](b: V#B => V) = b

这一次编译

f[C](a => new C())

但为什么这个不编译?

f(a => new C())

2 个答案:

答案 0 :(得分:1)

如果它在一个参数列表中推断出一个类型,那么该约束将在右侧的后续参数列表中使用。 (关于SO,请参阅许多类似的问题。)

但在参数列表中不会发生这种情况。

这不起作用:

scala> def g[V <: A](b: V => V#B) = b
g: [V <: A](b: V => V#B)V => V#B

scala> g((c: C) => "")
<console>:11: error: type mismatch;
 found   : String("")
 required: ?#B

?表示它尚未修复V,即使它刚刚解决V

对比:

scala> def k[V <: A](v: V)(f: V#B => V) = 42
k: [V <: A](v: V)(f: V#B => V)Int

scala> k(new C)(_ => new C)
res5: Int = 42

目前使用的选项是-Ytyper-debug。有时人们可以理解输出。

对于您的示例f(_ => new C),您可以看到它在x$1上立即失败,即使有人希望它回溯并自行更正。

|    |    |    |    |-- ((x$1) => new C()) : pt=?#B => ? BYVALmode-EXPRmode-POLYmode (site: value res0  in $iw) 
<console>:11: error: missing parameter type
              f(_ => new C)
                ^
|    |    |    |    |    |-- new C() EXPRmode (site: value $anonfun in $iw) 
|    |    |    |    |    |    |-- new C BYVALmode-EXPRmode-FUNmode-POLYmode (silent: value $anonfun in $iw) 
|    |    |    |    |    |    |    |-- new C EXPRmode-POLYmode-QUALmode (silent: value $anonfun in $iw) 
|    |    |    |    |    |    |    |    |-- C FUNmode-TYPEmode (silent: value $anonfun in $iw) 
|    |    |    |    |    |    |    |    |    \-> C
|    |    |    |    |    |    |    |    \-> C
|    |    |    |    |    |    |    \-> ()C
|    |    |    |    |    |    \-> C
|    |    |    |    |    \-> <error> => C
|    |    |    |    solving for (V: ?V)
|    |    |    |    \-> C#B => C

还有

http://www.scala-lang.org/files/archive/spec/2.11/06-expressions.html#local-type-inference

答案 1 :(得分:0)

我认为问题在于,是否将对象解释为CA类型是不明确的,因为它们都是A的上限。我想你可以争辩说编译器应该知道后者并不完全有意义,因为BA内是抽象的。但我能够让这个工作正常,直接在B引用A,而不是通过V

scala> trait A { type B }
defined trait A

scala> case class C() extends A { type B = String }
defined class C

scala> def f[V <: A](b: A#B => V) = b
f: [V <: A](b: A#B => V)A#B => V

scala> f(a => new C())
res0: A#B => C = <function1>