Scala - 在编译时强制执行 Vector 的大小 [英] Scala - Enforcing size of Vector at compile time
问题描述
是否可以强制在编译时传递给方法的 Vector
的大小?我想使用空间中看起来像这样的点集合来建模一个 n 维欧几里得空间(这就是我现在所拥有的):
Is it possible to enforce the size of a Vector
passed in to a method at compile time? I want to model an n-dimensional Euclidean space using a collection of points in the space that looks something like this (this is what I have now):
case class EuclideanPoint(coordinates: Vector[Double]) {
def distanceTo(desination: EuclieanPoint): Double = ???
}
如果我有一个通过 EuclideanPoint(Vector(1, 0, 0))
创建的坐标,它是一个 3D 欧几里得点.鉴于此,我想确保在对 distanceTo
的调用中传递的目标点具有相同的维度.
If I have a coordinate that is created via EuclideanPoint(Vector(1, 0, 0))
, it is a 3D Euclidean point. Given that, I want to make sure the destination point passed in a call to distanceTo
is of the same dimension.
我知道我可以通过使用 Tuple1
到 Tuple22
来做到这一点,但我想表示许多不同的几何空间,如果我要为每个空间编写 22 个类用 Tuple
s 做到的 - 有没有更好的方法?
I know I can do this by using Tuple1
to Tuple22
, but I want to represent many different geometric spaces and I would be writing 22 classes for each space if I did it with Tuple
s - is there a better way?
推荐答案
可以通过多种方式来做到这一点,这些方式或多或少都类似于 Randall Schulz 在评论中所描述的.Shapeless 库 提供了一个特别方便的实现,它可以让你得到非常接近你想要的东西:
It is possible to do this in a number of ways that all look more or less like what Randall Schulz has described in a comment. The Shapeless library provides a particularly convenient implementation, which lets you get something pretty close to what you want like this:
import shapeless._
case class EuclideanPoint[N <: Nat](
coordinates: Sized[IndexedSeq[Double], N] { type A = Double }
) {
def distanceTo(destination: EuclideanPoint[N]): Double =
math.sqrt(
(this.coordinates zip destination.coordinates).map {
case (a, b) => (a - b) * (a - b)
}.sum
)
}
现在您可以编写以下内容:
Now you can write the following:
val orig2d = EuclideanPoint(Sized(0.0, 0.0))
val unit2d = EuclideanPoint(Sized(1.0, 1.0))
val orig3d = EuclideanPoint(Sized(0.0, 0.0, 0.0))
val unit3d = EuclideanPoint(Sized(1.0, 1.0, 1.0))
还有:
scala> orig2d distanceTo unit2d
res0: Double = 1.4142135623730951
scala> orig3d distanceTo unit3d
res1: Double = 1.7320508075688772
但不是:
scala> orig2d distanceTo unit3d
<console>:15: error: type mismatch;
found : EuclideanPoint[shapeless.Nat._3]
required: EuclideanPoint[shapeless.Nat._2]
orig2d distanceTo unit3d
^
Sized
带有许多不错的特性,包括一些带有关于长度的静态保证的集合操作.例如,我们可以编写以下内容:
Sized
comes with a number of nice features, including a handful of collections operations that carry along static guarantees about length. We can write the following for example:
val somewhere = EuclideanPoint(Sized(0.0) ++ Sized(1.0, 0.0))
并且在三维空间中有一个普通的旧点.
And have an ordinary old point in three-dimensional space.
这篇关于Scala - 在编译时强制执行 Vector 的大小的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!