【问题标题】:Why scala does not unify this type lambda with underlying type?为什么 scala 不将这种类型的 lambda 与底层类型统一起来?
【发布时间】:2017-10-17 22:21:31
【问题描述】:
trait A {
  type T
  def test(t: T): Unit
}

case class B[S <: A](a: S, t : S#T) {
  def test() = a.test(t) // Error: type mismatch;
    // found   : B.this.t.type (with underlying type S#T)
    // required: B.this.a.T
}

我期望上面的编译是错误的吗?我的代码可以修复吗?

【问题讨论】:

    标签: scala existential-type


    【解决方案1】:

    编译器没有足够的证据证明S#T 在具体实例中可以用作test 的参数。

    考虑一下这个弱化 scala 编译器的假设示例

    trait A2 extends A{
      type T <: AnyRef
    }
    
    class A3 extends A2{
      override type T = Integer
    
      def test(t: Integer): Unit = println(t * 2)
    }
    

    所以B[A2] 应该接受A3 的实例以及&lt;: AnyRef 的任何内容,而A3 完全需要Integer 来实现自己的test 实现

    您可以在B的定义中捕获具体类型,以确定将使用哪种类型

    case class B[S <: A, ST](a: S {type T = ST}, t: ST) {
      def test() = a.test(t) 
    }
    

    【讨论】:

    • 但是B[A2](new A3(), "") 不能编译...你的意思是我的代码可以编译吗?否则你的解决方案正是我所需要的。
    • 哈,聪明的把戏!我不知道在细化中可以使用右手视线上的类型参数。
    • @JbGi 是的,我想了很多如何用一个实际编译的例子来证明这一点,但是 scala 编译器在这里非常严格。所以让这只是一个虚构的类 scala 编译器的虚构示例,它可以编译原始源
    • 通过强制转换强制 OP 版本编译无助于使 B[A2](new A3(), "") 编译,因为 String 不符合 A2#T
    【解决方案2】:

    我可以想出编码(为了简化去掉了类型参数):

    scala> :paste
    // Entering paste mode (ctrl-D to finish)
    
    def test0(a: A)(t : a.T) = a.test(t) 
    
    abstract class B{
      val a: A
      val t: a.T
      def test = a.test(t)
    }
    
    // Exiting paste mode, now interpreting.
    
    test0: (a: A)(t: a.T)Unit
    defined class B
    

    另一方面,这不适用于案例类参数(也不适用于类)。

    您的编码不起作用的原因之一:

    scala> def test1(a: A)(t : A#T) = a.test(t) 
    <console>:12: error: type mismatch;
     found   : t.type (with underlying type A#T)
     required: a.T
           def test1(a: A)(t : A#T) = a.test(t)
    

    重要的部分是required: a.T(相对于A#T)。 A 中的测试方法不带任何 T,它带 T this.T,或者换句话说,T 属于 A 的一个特定实例。

    【讨论】:

    • 谢谢!这有助于我更好地理解!那么a.T 是什么所谓的“路径依赖类型”?
    • 没错,这是一个依赖路径的类型。
    【解决方案3】:

    您可以使用依赖类型a.T,而不是类型投影:

    trait A {
      type T
      def test(t: T): Unit
    }
    
    case class B[S <: A](a: S)(t : a.T) {
      def test() = a.test(t)
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-07-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-04
      • 2018-12-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多