11

Vector是否可以在编译时强制传入方法的大小?我想使用空间中看起来像这样的点集合来建模一个 n 维欧几里得空间(这就是我现在所拥有的):

case class EuclideanPoint(coordinates: Vector[Double]) {
  def distanceTo(desination: EuclieanPoint): Double = ???
}

如果我有一个通过 创建的坐标,则EuclideanPoint(Vector(1, 0, 0))它是一个 3D 欧几里得点。鉴于此,我想确保在调用中传递的目标点具有distanceTo相同的维度。

我知道我可以使用Tuple1to来做到这一点Tuple22,但我想表示许多不同的几何空间,如果我用Tuples 来做,我将为每个空间编写 22 个类 - 有更好的方法吗?

4

2 回答 2

12

可以通过多种方式来做到这一点,这些方式都或多或少像 Randall Schulz 在评论中描述的那样。Shapeless提供了一个特别方便的实现,它可以让你得到非常接近你想要的东西,如下所示:

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
    )
}

现在您可以编写以下内容:

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带有许多不错的功能,包括一些带有关于长度的静态保证的集合操作。例如,我们可以编写以下内容:

val somewhere = EuclideanPoint(Sized(0.0) ++ Sized(1.0, 0.0))

并且在三维空间中拥有一个普通的老点。

于 2013-02-07T00:52:09.197 回答
2

您可以通过对自然数进行类型级编码来自己做一些事情,例如:http ://apocalisp.wordpress.com/2010/06/08/type-level-programming-in-scala/ 。然后只需通过自然参数化您的矢量。不需要额外的依赖,但可能会比使用 Shapeless 更复杂。

于 2013-02-07T04:59:14.500 回答