Как определить вспомогательные типы, независимые от пути в классе типов Scala? - PullRequest
1 голос
/ 18 июня 2020

Давайте иметь класс типа, который в зависимости от типа определяет еще несколько типов для работы:

trait Container[T] {
  type Elem

  def get(c: T, i: Int): Elem
  def set(c: String, i: Int, v: Elem): T
}

implicit object StringContainer extends Container[String] {
  type Elem = Char

  def get(c: String, i: Int) = c(i)
  def set(c: String, i: Int, v: Char) = c.patch(i, Seq(v), 1)
}

val ops = implicitly[Container[String]]


ops.set("ABC", 1, ops.get("ABC", 1)) // works

ops.set("ABC", 1, 'X') // type mismatch; found   : Char('X') required: ops.Elem

Поскольку типы зависят от пути, компилятор жалуется при попытке использовать это, ошибка:

несоответствие типов;

найдено: Char ('X')

требуется: ops.Elem

Мы с вами знаем ops.Elem это Char. Мой текущий обходной путь - вместо этого использовать Elem в качестве параметра типа:

trait Container[T, Elem] {
  def get(c: T, i: Int): Elem
  def set(c: String, i: Int, v: Elem): T
}

implicit object StringContainer extends Container[String, Char] {
  def get(c: String, i: Int) = c(i)
  def set(c: String, i: Int, v: Char) = c.patch(i, Seq(v), 1)
}

Недостаток заключается в том, чтобы вспомнить класс типа, когда это необходимо, необходимо предоставить все аргументы типа:

val ops = implicitly[Container[String, Char]]

Есть ли способ определить типы в тип-классе, чтобы их можно было использовать как независимые от пути?

1 Ответ

2 голосов
/ 18 июня 2020

Вы запрашиваете только

Container[String]

вместо

Container[String] { type Elem = Char }

Попробуйте с уточнением типа

object Container {
  implicit val strContainer: Container[String] { type Elem = Char } = new Container[String] {
    type Elem = Char

    def get(c: String, i: Int) = c(i)
    def set(c: String, i: Int, v: Char) = c.patch(i, Seq(v), 1)
  }
}

val ops = implicitly[Container[String] { type Elem = Char }]
ops.set("ABC", 1, 'X') // ok

, которое с шаблоном Aux становится чем-то вроде

object Container {
  type Aux[T,Elem0] = Container[T] { type Elem = Elem0 }

  implicit val strContainer: Aux[String, Char] = new Container[String] {
    type Elem = Char

    def get(c: String, i: Int) = c(i)
    def set(c: String, i: Int, v: Char) = c.patch(i, Seq(v), 1)
  }
}


val ops = implicitly[Container.Aux[String,Char]]
ops.set("ABC", 1, 'X') // ok
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...