下划线类型的推断

时间:2018-12-10 14:50:16

标签: scala types type-inference shapeless

[我无法用更少的冗长来解释这个问题。问题的核心是编译器推断出下划线(_)类型。特别是[_ >: SomeType <: SomeOtherType]。我不知道何时,如何以及为什么这样]

作为scala练习,我正在尝试对给定大小的元素向量进行编码。
作为必要的步骤,我首先复制了现有的自然数编码:

sealed trait Natural extends Product with Serializable {
  def +(that: Natural): Natural
}

case object Zero extends Natural {
  override def +(that: Natural): Natural = that
}

final case class Suc[N <: Natural](n: N) extends Natural {
  override def +(that: Natural): Natural = Suc(n + that)
}

我相信下图是对类型关系的忠实描绘:
enter image description here 然后,我尝试对由元素上的类型和大小上的另一种类型参数化的向量建模。不过,为了解释这个问题,我假定了一个ints向量,并且仅参数化了该向量的大小:

import shapeless.=:!=  

sealed trait Vector[+Size <: Natural] extends Product with Serializable {
  def head: Int
  def tail: Vector[Natural]

  def plus[OtherSize >: Size <: Natural]
  (that: Vector[OtherSize])
  (implicit ev: OtherSize =:!= Natural): Vector[OtherSize]
}

case object VectorNil extends Vector[Zero.type] {
  override def head: Nothing = throw new Exception("Boom!")
  override def tail: Vector[Zero.type] = throw new Exception("Boom")

  override def plus[OtherSize >: Zero.type <: Natural]
  (that: Vector[OtherSize])
    (implicit ev: =:!=[OtherSize, Natural]): Vector[OtherSize] = this

}

final case class VectorCons[N <: Natural](
  head: Int,
  tail: Vector[N]
) extends Vector[Suc[N]] {

  override def plus[OtherSize >: Suc[N] <: Natural]
  (that: Vector[OtherSize])
    (implicit ev: =:!=[OtherSize, Natural]): Vector[OtherSize] = that
}

请注意,VectorCons[N]实际上是大小为Suc[N]的向量。 (扩展Vector[Suc[N]])。
方法plus应该添加两个相同大小的向量的元素。我想将类型总和相同的向量求和提高到类型级别。
请注意,类型边界OtherSize >: Size <: Natural与隐式证据的结合应该可以实现这一点(请参见底部的类似示例),但是:

val foo = VectorCons(1, VectorCons(2, VectorNil))
//type -> VectorCons[Suc[Zero.type]]
// note that foo is (can be viewed) as Vector[Suc[Suc[Zero.type]], i.e
// a vector of 2 elements

val bar = VectorCons(3, VectorNil)
//type -> VectorCons[Zero.type]

val baz = foo.plus(bar)
//type -> Vector[Suc[_ >: Suc[Zero.type] with Zero.type <: Natural]]  !! How is this possible ?? !!

让我感到沮丧的是,baz编译得很好!无形的类型约束无效。好吧,因为OtherSize确实与Natural不同;特别是Suc[_ >: Suc[Zero.type] with Zero.type <: Natural]
因此,我对baz的类型非常困惑!这就是可以绕开约束的原因。

  1. 编译器针对baz / bar类型推断出什么?
  2. 是存在类型吗?
  3. 编译器是否可以推断此类情况?
  4. 这不是不良行为吗?

在这一点上,我不关心这是否是向量的正确编码。只是想了解编译器如何为baz推断该类型?

p.s
1-我知道在VectorCons上实现方法that返回的plus并没有达到plus语义所暗示的含义,但这对问题并不重要。

######额外#######
我怀疑这种奇怪的行为(至少对我而言)与自然数有关。下面的代码工作正常! :
[忽略代码的荒谬语义]

  sealed trait Animal extends Product with Serializable
  case class Dog() extends Animal
  case class Cow() extends Animal
  case object NoBox extends Animal //Not important

trait Vector[+A <: Animal] {
  def head: A

  def plus[That >: A <: Animal]
  (that: Vector[That])
    (implicit ev: =:!=[That, Animal]): Vector[That]
}

case object Nil extends Vector[NoBox.type] {
  def head: Nothing = throw new NoSuchElementException("Boom!")

  override def plus[That >: NoBox.type <: Animal]
  (that: Vector[That])(implicit ev: =:!=[That, Animal]): Vector[That] = this
}

case class Cons[A <: Animal](head: A) extends Vector[A] {

  override def plus[That >: A <: Animal]
  (that: Vector[That])(implicit ev: =:!=[That, Animal]): Vector[That] = that
}

其中:

val foo = Cons(Dog())
val bar = Cons(Cow())

// Compiles
val baz = foo.plus(foo)
val baz2 = bar.plus(bar)

// Does not compile  (what I would expect)  
val baz3 = bar.plus(foo)
val baz4 = foo.plus(bar)

感谢您的输入,

0 个答案:

没有答案