我正在编写一个用于复杂向量计算的数学库,其中一部分如下所示:
object Example1 {
val two = 2
val three = 3
// SU means 'special unitary group'
trait SU_n[D <: Int] {
def plus(v1: ComplexVector[D], v2: ComplexVector[D])(
implicit ev: D =:= two.type
): ComplexVector[D] = {
//TODO: some unspeakable magic here
???
}
}
class ComplexVector[D <: Int: ClassTag](xyzw: List[(Double, Double)]) {
{
assert(xyzw.size.isInstanceOf[D])
}
}
type Quaternion = ComplexVector[two.type]
val alsoTwo = 2
object SU_2 extends SU_n[two.type] {}
object SU_Also2 extends SU_n[alsoTwo.type] {}
object SU_3 extends SU_n[three.type] {}
val q = new Quaternion(List(1.0 -> 2.0, 3.0 -> 4.0))
{
val v2 = SU_2.plus(q, q)
val also_v2 = SU_Also2.plus(q, q)
}
val vec =
new ComplexVector[three.type](List(1.0 -> 2.0, 3.0 -> 4.0, 5.0 -> 6.0))
// This will break
// {
// val v3 = SU_3.plus(vec, vec)
// }
}
中缀类型
=:=
用于确保函数plus
不能用于四元数以外的向量,当我编译它时,我收到以下错误消息:Error: type mismatch;
found : <mypackage>.Example1.two.type (with underlying type Int)
required: AnyRef
type Quaternion = ComplexVector[two.type]
奇怪的是我在中缀类
=:=
的实现中找不到任何地方要求其操作数为 AnyVal
,那为什么我会收到这个错误?以及如何修复/绕过它以达到要求? (即创建一个只能应用于四元数的函数)
最佳答案
由 .type
生成的单例类型不要以您想象的方式工作 - 特别是,它们不是文字类型。要看到这一点,请验证:
val two = 2
val alsoTwo = 2
type V = two.type
type W = alsoTwo.type
implicitly[V =:= W] // will fail with an implicit error
val test : V = 2 // will fail with "expression does not conform to type"
def id(x: V) : W = x //will fail with "expression does not conform to type"
从历史上看,这个
.type
语法仅用于 AnyRef
,编译器不会公开原始类型的单例类型。从 2.13 开始,这已经改变了,语言现在支持文字类型,但它看起来像 .type
的行为。还是一样。如果 2.13 是一个选项,你可以只写
trait SU_n[D <: Int] {
def plus(v1: ComplexVector[D], v2: ComplexVector[D])(
implicit ev: D =:= 2
): ComplexVector[D] = {
//TODO: some unspeakable magic here
???
}
}
type Quaternion = ComplexVector[2]
object SU_2 extends SU_n[2] {}
object SU_Also2 extends SU_n[2] {}
object SU_3 extends SU_n[3] {}
一切都会按预期进行。如果您需要坚持使用 2.11 或 2.12,我建议您查看 shapeless如果这是你想走的路线。
也就是说,根据我的评论,这似乎是解决问题的一种非常奇怪的方法,因为具有特征的想法
T[A] { def foo(a: A) }
哪里打电话foo
仅在 A
时才编译是一种特定的类型让我觉得相当病态。如果你真的想要一个 plus
方法只能访问四元数,你可以做类似的事情implicit class QuaternionSupport(quaternions: SU_n[2]) {
def plus(quaternion1: Quaternion, quaternion2: Quaternion) : Quaternion = ???
}
并且该方法不会用于其他维度。
关于scala - 在 Scala 2.11+ 中如何准确地使用单例类型作为类型证据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56657977/