Scala中的Abstrac类型和路径依赖类型

时间:2018-07-24 23:34:33

标签: scala types path-dependent-type abstract-type

我想使用抽象类型和类型细化对两种类型之间的函数依赖进行编码。

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类型这一事实?或者如何防止M中的def f(m: M): Unit成为路径相关类型?

谢谢!

1 个答案:

答案 0 :(得分:1)

认为,该问题来自b与类型T的关联,a可能是子类< T的/ em>可能会覆盖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())
}