scala中的抽象类型和路径依赖类型

Abstract type and path dependent type in scala

我想使用抽象类型和类型细化来编码类似于两种类型之间的函数依赖性的东西。

trait BaseA {
  type M
  type P <: BaseB.Aux[M]

  def f(m: M): Unit
}

trait BaseB {
  type M
  def m(): M
}

object BaseB {
  type Aux[M0] = BaseB { type M = M0 }
}

这意味着 A 只能与 B 一起使用,前提是它们内部具有相同的类型 M。 具体如下 类

class A extends BaseA {
  type M = Int
  type P = B

  def f(m: Int): Unit = {
    println("a")
  }
}

class B extends BaseB {
  type M = Int
  def m(): M = 1
}

所以现在它们的 Int 类型都为 M,但是下面的代码无法编译

val a: BaseA = new A
val b: BaseB = new B

def f[T <: BaseA](a: T, b: T#P): Unit = {
  a.f(b.m())
}

编译器告诉我 a.f 这里需要一个路径依赖类型 a.M 但它得到了 b.M

我的问题是如何表达我只需要在类型级别而不是实例级别匹配的 M 类型这一事实?或者如何防止 def f(m: M): Unit 中的 M 成为路径依赖类型?

谢谢!

认为问题来自b与类型T相关,并且a可能是T 子类 可以将 M 覆盖为其他对象,从而使两个对象不兼容。例如:

class A2 extends BaseA {
  type M = String
  type P = B2
  def f(s: String): Unit = {
    println(s)
  }
}

class B2 extends BaseB {
  type M = String
  def m(): M = "foo"
}

val a: BaseA = new A
val b: BaseB = new B2

f[BaseA](a, b)

似乎如果您的 f 可以编译,那么所有这些也应该可以编译。

您可以使 b 的类型依赖于 a.P:

def f(a: BaseA)(b: a.P): Unit

或者我认为整个事情通过对你的 类 没有兼容类型限制而得到简化,而是要求一个是另一个在它们交互时的子类:

trait BaseA {
  type M
  def f(m: M): Unit
}

trait BaseB {
  type M
  def m(): M
}

class A extends BaseA {
  type M = Int
  def f(m: Int): Unit = {
    println("a")
  }
}

class B extends BaseB {
  type M = Int
  def m(): M = 1
}

val a: A = new A
val b: B = new B

def f(a: BaseA, b: BaseB)(implicit sub: b.M <:< a.M): Unit = {
  a.f(sub(b.m()))
}

f(a, b)

或者最后,考虑一下你是否需要这些是路径相关的类型;它们可以是常规的泛型类型参数吗?

trait BaseA[-M] {
  def f(m: M): Unit
}

trait BaseB[+M] {
  def m(): M
}

class A extends BaseA[Int] {
  def f(m: Int): Unit = {
    println("a")
  }
}

class B extends BaseB[Int] {
  def m(): Int = 1
}

def f[T](a: BaseA[T], b: BaseB[T]): Unit = {
  a.f(b.m())
}