Несоответствие типов для реализации безопасных векторов - PullRequest
0 голосов
/ 04 ноября 2018

Я пытаюсь реализовать векторы уровня типа. Все работало хорошо, пока я не попытался реализовать функцию add, которая предназначена для добавления двух векторов (одинаковых размеров).

Это то, что я имею до сих пор:

object Vector {

  type Vector1[A] = Ex[A, Vector0[A]]

  def of[A](a1: A): Vector1[A] = Ex(Vector0[A](), a1)

  type Vector2[A] = Ex[A, Vector1[A]]

  def of[A](a1: A, a2: A): Vector2[A] = of(a1).ex(a2)

  type Vector3[A] = Ex[A, Vector2[A]]

  def of[A](a1: A, a2: A, a3: A): Vector3[A] = of(a1, a2).ex(a3)

}

trait Vector[A] {

  type Same[B] <: Vector[B]
  type Self <: Vector[A]

  def ex(a: A): Vector[A]

  def add(that: Self): Self

  def map[B](f: A => B): Same[B]

  def forEach(f: A => Unit): Unit
}

case class Vector0[A]() extends Vector[A] {

  type Same[B] = Vector0[B]
  type Self = Vector0[A]

  def ex(that: A): Ex[A, Self] = Ex[A, Self](this, that)

  def add(that: Self): Self = Vector0[A]()

  def map[B](f: A => B): Same[B] = Vector0[B]()

  def forEach(f: A => Unit): Unit = ()
}

case class Ex[A, V <: Vector[A]](v: V, a: A) extends Vector[A] {

  type Same[B] = Ex[B, V#Same[B]]
  type Self = Ex[A, V]

  def ex(that: A): Ex[A, Self] = Ex[A, Self](this, that)

  def add(that: Self)(implicit num: Numeric[A]): Self = Ex[A, V](v.add(that.v), num.plus(a, that.a))

  def map[B](f: A => B): Same[B] = Ex[B, V#Same[B]](v.map(f), f(a))

  def forEach(f: A => Unit): Unit = {
    v.forEach(f)
    f(a)
  }
}

Это больше кода, чем может понадобиться для решения проблемы, но он может быть полезен для любого обсуждения.

Теперь взгляните на add в Ex («ex» означает «выдавливание», например, добавление еще одного измерения к вектору).

Я получаю следующую ошибку компиляции:

[error]  found   : that.v.type (with underlying type V)
[error]  required: Ex.this.v.Self
[error]   def add(that: Self)(implicit num: Numeric[A]): Self = Ex[A, V](v.add(that.v), num.plus(a, that.a))
                                                                                    ^

Это не имеет смысла для меня, так как оба типа v и that.v гарантированно имеют тип V.

Я использую mill с Scala 2.13.0-M5.

Чего мне не хватает?

1 Ответ

0 голосов
/ 07 ноября 2018

Проблема в том, что тип Self в Vector является абстрактным и определяется только для неабстрактного подкласса Vector. У вас могут быть значения типа Vector, но компилятор не может знать тип Self для этого значения. Поэтому вы не можете вызвать add для этого значения, потому что невозможно проверить, что аргумент является правильным типом (потому что тип неизвестен).

В вашем классе Ex значение v имеет тип V <: Vector[A], что означает, что оно может быть Vector[A]. Но add не определено для Vector[A], потому что Self не определено, поэтому компилятор жалуется, когда вы пытаетесь вызвать v.add.

Вот упрощенный пример:

 trait A {
   type Self // Abstract type
   def add(a: Self, b: Self): Self
 }

 case class A1() extends A {
   type Self = Int // Concrete type
   def add(a: Int, b: Int) = a + b
 }

 case class A2() extends A {
   type Self = String // Concrete type
   def add(a: String, b: String) = a + b
 }

 val a1 = new A1
 val a2 = new A2

 a1.add(1, 1) // Argument type is Int

 a2.add("A", "B") // Argument type is String

Это все работает нормально, потому что типы известны. Но теперь сделайте значение типа A и вызовите add для этого:

 val a: A = a1
 a.add(1, 1) // fails to compile
 a.add("A", "B") // fails to compile

Это не компилируется, потому что вы потеряли информацию о типе для Self, потому что в A она является абстрактной.

Проще говоря, вы не можете вызвать метод, аргументы которого объявлены как абстрактные типы.

...