【问题标题】:Why would the Scala compiler consider a type, and the type of a value assigned it to be different?为什么 Scala 编译器会考虑一个类型,而分配给它的值的类型是不同的?
【发布时间】:2021-02-24 01:50:49
【问题描述】:

我有一个表示向量的简单类,这样不同长度的向量可以解析为不同的类型。但是,我在实施 zip 方法时遇到了一些困难。这是我所做工作的最小化版本,以及我觉得有点神秘的编译器消息。

  sealed trait Vector[A] {

    type ThisButType[B] <: Vector[B]

    def zip[B](other: ThisButType[B]): ThisButType[Tuple2[A, B]]
  }

  case class Term[A]() extends Vector[A] {
   
    type ThisButType[B] = Term[B]
   
    def zip[B](other: ThisButType[B]): ThisButType[Tuple2[A, B]] = Term[Tuple2[A, B]]()
  
  }

  case class Component[A, T <: Vector[A]](value: A, tail: T) extends Vector[A]{

    type ThisButType[B] = Component[B, T#ThisButType[B]]

    def zip[B](other: ThisButType[B]): ThisButType[Tuple2[A, B]] =
      Component[Tuple2[A,B], T#ThisButType[Tuple2[A, B]]]((value, other.value), tail.zip(other.tail))
  }

我得到的错误是:

 type mismatch;
   found   : other.tail.type (with underlying type T#ThisButType[B])
   required: Component.this.tail.ThisButType[B]

为什么编译器无法确定在这种情况下 T 应该与 Component.this.tail 相同?

【问题讨论】:

    标签: scala types higher-kinded-types


    【解决方案1】:

    假设是这样:

    // applying some other minor changes...
    sealed trait Vector[A] {
        type ThisButType[B] <: Vector[B]
        def zip[B](other: ThisButType[B]): ThisButType[(A, B)]
    }
    case class Term[A]() extends Vector[A] {
        override type ThisButType[B] = Term[B]
        override def zip[B](other: Term[B]): Term[(A, B)] = Term()
    }
    case class Component[A, T <: Vector[A]](value: A, tail: T) extends Vector[A] {
        override type ThisButType[B] = Component[B, T#ThisButType[B]]
        override def zip[B](other: Component[B, T#ThisButType[B]]): Component[(A, B), T#ThisButType[(A, B)]] =
            Component((value, other.value), tail.zip(other.tail.asInstanceOf[tail.ThisButType[B]]))
    }
    

    然后……

    val zero = Term[Unit]()
    val zero0: Vector[Unit]#ThisButType[Int] = Term[Int](): zero.ThisButType[Int] // the mystical double type ascription!
    val two = Component((), Component((), Term[Unit]()): Vector[Unit])
    two.zip(Component(0, zero0)) // ClassCastException!
    

    因此,您的代码确实存在类型错误,编译器将其视为错误而拒绝是正确的。具体来说,您的代码中的T#ThisButType[B]tail.ThisButType[B] 完全相同,因为tail 不必是精确类型T,但可以是某个子类型。在这种情况下,T#ThisButType[B] 可以包含 tail.ThisButType[B] 不包含的值,这意味着您不能将前者 (other.tail) 传递给需要后者的函数 (tail.zip)。

    故事的寓意:类型投影是邪恶的,应该避免。你有一个非常好的价值 tail: T 就在那里;只是从那个项目。

    // applying some more minor changes...
    sealed trait Vector[+A] {
        type ThisButType[+B] <: Vector[B]
        def zip[B](other: ThisButType[B]): ThisButType[(A, B)]
    }
    case object Term extends Vector[Nothing] {
        override type ThisButType[+B] = Term.type
        override def zip[B](other: Term.type): Term.type = Term
    }
    case class Component[+A, +T <: Vector[A]](value: A, tail: T) extends Vector[A] {
        override type ThisButType[+B] = Component[B, tail.ThisButType[B]]
        override def zip[B](other: Component[B, tail.ThisButType[B]]): Component[(A, B), tail.ThisButType[(A, B)]] =
            Component((value, other.value), tail.zip(other.tail))
    }
    

    之前的例子不再有效:

    val zero: Vector[Unit]#ThisButType[Int] = Term: Term.ThisButType[Int]
    val two = Component((), Component((), Term): Vector[Unit])
    two.zip(Component(0, zero)) // fails: don't know that zero: two.tail.ThisButType[Int]
    

    现在代码是正确的。

    【讨论】:

    • 谢谢,我也尝试过使用tail,但会导致不同但相似的问题,即zip 不会接受Component[X, Component[X, Term]] 类型的值。我开始认为这整个想法是不可能的,而且你不能有类型向量。
    • ?也许这值得一个单独的问题,但对我来说,至少像Component(1, Component(2, Term)).zip(Component('1', Component('2', Term))) 这样的基本东西是有效的。您可能需要在 Vector 中添加额外的“证明”以获得更高级的内容,例如 def idemThisButType[A, B]: ThisButType[A]#ThisButType[B] =:= ThisButType[B](我认为这是真的......)
    • @Lucas 您的zip 不是实际的zip,它会将向量切割成最短的向量。您的 zip 仅针对相同长度的向量进行编译。
    • @DmytroMitin 如果需要截断 zip,那么我会尝试使用类型级别的自然方法而不是这种方法。
    • @HTNW 是的,它适用于值,但会导致依赖于 zip 的函数出现很多问题。我不知道我可以告诉编译器这样的事情,听起来这可能就是我要找的。​​span>
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-03-26
    • 2020-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-24
    相关资源
    最近更新 更多