これは、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))
そして、三次元空間に普通の古い点を持ってください。