scala - 类型安全向量实现的类型不匹配
问题描述
我正在尝试实现类型级向量。在我尝试实现函数之前add
,这一切都很好,这意味着添加两个向量(相同维度)。
这是我到目前为止所拥有的:
object Vector {
type Vector1[A] = Ex[A, Vector0[A]]
def of[A](a1: A): Vector1[A] = Ex(Vector0[A](), a1)
type Vector2[A] = Ex[A, Vector1[A]]
def of[A](a1: A, a2: A): Vector2[A] = of(a1).ex(a2)
type Vector3[A] = Ex[A, Vector2[A]]
def of[A](a1: A, a2: A, a3: A): Vector3[A] = of(a1, a2).ex(a3)
}
trait Vector[A] {
type Same[B] <: Vector[B]
type Self <: Vector[A]
def ex(a: A): Vector[A]
def add(that: Self): Self
def map[B](f: A => B): Same[B]
def forEach(f: A => Unit): Unit
}
case class Vector0[A]() extends Vector[A] {
type Same[B] = Vector0[B]
type Self = Vector0[A]
def ex(that: A): Ex[A, Self] = Ex[A, Self](this, that)
def add(that: Self): Self = Vector0[A]()
def map[B](f: A => B): Same[B] = Vector0[B]()
def forEach(f: A => Unit): Unit = ()
}
case class Ex[A, V <: Vector[A]](v: V, a: A) extends Vector[A] {
type Same[B] = Ex[B, V#Same[B]]
type Self = Ex[A, V]
def ex(that: A): Ex[A, Self] = Ex[A, Self](this, that)
def add(that: Self)(implicit num: Numeric[A]): Self = Ex[A, V](v.add(that.v), num.plus(a, that.a))
def map[B](f: A => B): Same[B] = Ex[B, V#Same[B]](v.map(f), f(a))
def forEach(f: A => Unit): Unit = {
v.forEach(f)
f(a)
}
}
这可能比解决问题所需的代码多,但它可能对任何讨论都有帮助。
现在,看一下add
in Ex
(“ex”代表“extrude”,例如向向量添加一个维度)。
我收到以下编译错误:
[error] found : that.v.type (with underlying type V)
[error] required: Ex.this.v.Self
[error] def add(that: Self)(implicit num: Numeric[A]): Self = Ex[A, V](v.add(that.v), num.plus(a, that.a))
^
这对我来说没有意义,因为两者v
都that.v
保证是 type V
。
我正在使用mill
Scala 2.13.0-M5
。
我错过了什么?
解决方案
问题是 in 的类型Self
是Vector
抽象的,并且只为 的非抽象子类定义Vector
。您可以拥有类型的值,Vector
但编译器无法知道该Self
值的类型。因此,您不能调用add
该值,因为无法检查参数是否是正确的类型(因为类型未知)。
在您的Ex
班级中,值v
是 typeV <: Vector[A]
这意味着它可能是Vector[A]
. But add
is not defined forVector[A]
因为Self
没有定义,所以当你尝试调用时编译器会报错v.add
。
这是一个简化的示例:
trait A {
type Self // Abstract type
def add(a: Self, b: Self): Self
}
case class A1() extends A {
type Self = Int // Concrete type
def add(a: Int, b: Int) = a + b
}
case class A2() extends A {
type Self = String // Concrete type
def add(a: String, b: String) = a + b
}
val a1 = new A1
val a2 = new A2
a1.add(1, 1) // Argument type is Int
a2.add("A", "B") // Argument type is String
这一切都很好,因为类型是已知的。但是现在创建一个类型的值A
并调用add
它:
val a: A = a1
a.add(1, 1) // fails to compile
a.add("A", "B") // fails to compile
这不会编译,因为您丢失了类型信息,Self
因为A
它是抽象的。
简而言之,您不能调用其参数被声明为抽象类型的方法。
推荐阅读
- python - 通过在 Python 中的 dict 的 dict 列表中搜索另一个值来返回一个值
- angular6 - Angular 6 - 如何提交表单的一个区域(但不是整个表单)
- ios - 无论纵横比如何,Endless Runner 都会重新定位播放器以获得相同的难度
- java - JPA创建Schema后如何让组件初始化?
- php - 使用 PHP 从 HEIC 照片中读取 EXIF 数据
- javascript - 为什么这个 forEach 循环嵌套?
- javascript - 在 HTML 网页上滚动播放 Lottie / Bodymovin 动画
- java - 如何使用动作监听器从按钮获取背景颜色
- gremlin - Gremlin:如何在同一条边上向后遍历
- python - 如何解决“ValueError:无法转换为 Excel”?(使用 Python 和 openpyxl)?