2013-02-06 26 views
9

是否有可能強制在編譯時傳遞給方法的Vector的大小?我想模擬使用,看起來像這樣的空間中的點的集合,n維歐幾里德空間(這是我現在有):Scala - 在編譯時強制實現向量的大小

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

如果我有一個通過EuclideanPoint(Vector(1, 0, 0))創建一個座標,它是一個3D歐幾里德點。鑑於此,我想確保通過調用distanceTo傳遞的目標點具有相同的維度。

我知道我可以通過使用Tuple1Tuple22做到這一點,但我要代表許多不同的幾何空間,我會寫22班每個空間,如果我有Tuple小號做到了 - 有沒有更好的辦法?

+1

我不能很好地意識到這是一個_answer_,但它可能有資格作爲一個想法......我想到的第一件事是將一個Value Class(2.10中的new)和路徑依賴類型結合起來代表特定整數的類型。我真的不知道這是否可以起作用。當工作結束的時候,我可能會嘗試一下...請參閱SIP 15:http://docs.scala-lang.org/overviews/core/value-classes.html –

+0

這種約束可以用「類型編程」。例如,請參閱[Apocalisp博客系列](http://apocalisp.wordpress.com/2010/06/08/type-level-programming-in-scala/),特別是HList。 –

回答

11

可以通過很多方式做到這一點,所有這些看起來都像Randall Schulz在評論中所描述的那樣。該Shapeless library提供了一個特別方便的實現,它可以讓你想這樣你會得到什麼很接近的東西:

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

並且在三維空間中有一個普通的老點。

+0

太棒了,謝謝!快速問題 - 是否可以將一個'IndexedSeq [Double]'轉換爲'Sized'版本?我正在深入研究代碼,無法搞清楚。 – adelbertc

+0

問題:無形需要預發佈/快照/新生Scala 2.11嗎?因爲當我檢索它並構建它時,它使用了2.11快照Scala。 (另外,它不能編譯,但我不確定它是怎麼回事) –

+0

不,你可以通過SBT或Maven獲得版本1.2.3的Shapeless for 2.10.0(或2.9.2)依賴關係,或者通過檢查'shapeless-1.2.3'標籤並構建它。 –