【问题标题】:Why scala compiler doesn't infer type with abstract type为什么scala编译器不使用抽象类型推断类型
【发布时间】:2014-10-09 21:41:26
【问题描述】:

给定以下代码

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())

【问题讨论】:

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


    【解决方案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(_ =&gt; 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

    【讨论】:

      【解决方案2】:

      我认为问题在于将您的对象解释为CA 类型是不明确的,因为两者的上限都是A。我猜你可能会争辩说编译器应该知道后者并不完全有意义,因为BA 中是抽象的。但我能够让它工作,直接在A 中引用B,而不是通过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>
      

      【讨论】:

      • 公平地说,你只问了为什么底线不编译。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-02-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-10
      相关资源
      最近更新 更多