Общая фабрика типов высшего порядка Scala

Я снова играл со scala, тестируя некоторые функции проверки типа языка. Я пытаюсь реализовать векторную библиотеку, предназначенную для использования с графикой, и я хочу максимально использовать средство проверки типов scala, чтобы при его использовании получать ранние предупреждения о времени компиляции. Что у меня есть до сих пор.

trait VecT

abstract sealed class Vec[T,V[T] <: VecT](elems: T*)(implicit num: VecIntegral[T]) extends VecT {
  import num._

  def +(v: V[T]): V[T] = ???
  def -(v: V[T]): V[T] = ???
  def cross(v: V[T]): V[T] = ???
  def dot(v: V[T]): T = ???
  def unary_-(): V[T] = ???
  def *(scalar: T): V[T] = ???
  def abs: T = ???
  def *(v: V[T]): V[T] = cross(v)
  def apply(n: Int): T = ???
}

class Vec2[T](x: T, y: T)(implicit num: VecIntegral[T]) extends Vec[T, Vec2](x,y)
class Vec3[T](x: T, y: T, z: T)(implicit num: VecIntegral[T]) extends Vec[T, Vec3](x,y,z)

это позволяет мне выполнять проверку времени компиляции для операций, например, даже если оператор + реализован в классе abstract

(new Vec3[Int](1,2,3)) + (new Vec3[Int](1,2,3))
(new Vec3[Int](1,2,3)) + (new Vec2[Int](1,2)) // Failes compilation

чего я хочу.

Все идет нормально. Теперь я хотел бы, чтобы функция карты была реализована в абстрактном классе, например

def map[A](f: T => A): V[A] = Vec(elems.map(f):_*)

Так что моя попытка реализовать это состояла бы в том, чтобы создать общую фабрику Vec.

object Vec {
  def apply[T, V[T] <: VecT](elemes: T*)(implicit num: VecIntegral[T]): V[T] = elems match {
    case Seq(x,y)   => new V[T](x,y)
    case Seq(x,y,z) => new V[T](x,y,z)
}

но это не сработает, expression of type V does not comform to exptected type V[T]

Итак, мой вопрос. Есть ли какой-нибудь «хороший» общий способ реализации такой фабрики?


person Patrik    schedule 02.09.2016    source источник


Ответы (1)


Почему new V[T](...) не работает и не должен работать, см. https://stackoverflow.com/a/39286308/9204. . Одним из решений было бы

trait VecFactory[V[_]] { def newVec[T](elems: Seq[T]): V[T] }

abstract sealed class Vec[T,V[T] <: VecT](elems: T*)(implicit num: VecIntegral[T], factory: VecFactory[V]) {
  def map[A](f: T => A): V[A] = factory.newVec(elems.map(f))
}
class Vec2[T](x: T, y: T)(implicit num: VecIntegral[T]) extends Vec[T, Vec2](x,y)
object Vec2 {
  implicit val factory: VecFactory[Vec2] = new VecFactory[Vec2] { 
    def newVec[T](elems: Seq[T]) = new Vec2(elems(0), elems(1))
  }
}

class Vec3[T](x: T, y: T, z: T)(implicit num: VecIntegral[T]) extends Vec[T, Vec3](x,y,z)
object Vec3 {
  implicit val factory: VecFactory[Vec3] = ...
}

Обратите внимание, что это все еще не совсем безопасно: фабрики должны вызываться последовательностями определенной длины.

person Alexey Romanov    schedule 02.09.2016
comment
Я понимаю, к чему вы клоните, но trait VecFactory[V] { def newVec[T](elems: Seq[T]): V[T] } жалуется на то, что V не принимает никаких параметров, а Vec3 принимает параметр типа в new VecFactory[Vec3] - person Patrik; 02.09.2016
comment
Извините, исправил синтаксис. - person Alexey Romanov; 02.09.2016
comment
Спасибо, теперь заработало! Суть в том, что я получил gist.github.com/kaffepanna/948bb80ef7038a5fbda1a4171a07ccdf - person Patrik; 02.09.2016