如何在 Scala 类型 class 中定义与路径无关的辅助类型?

How to define a helper types to be path-independent in a Scala type class?

让我们有一个类型 class,它根据类型定义了更多类型:

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

因为类型依赖于路径,编译器在尝试使用它时会报错,错误是:

type mismatch;

found : Char('X')

required: ops.Elem

你我都知道 ops.ElemChar。我当前的解决方法是使用 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)
}

缺点是在需要时调用类型 class 需要提供所有类型参数:

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

是否有一些方法可以在 type-class 中定义类型,以便它们可以用作路径无关的?

您只需要

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