Scala - Enforcing size of Vector at compile time

后端 未结 2 1089
不思量自难忘°
不思量自难忘° 2021-01-02 02:58

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 poi

相关标签:
2条回答
  • 2021-01-02 03:35

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

    And:

    scala> orig2d distanceTo unit2d
    res0: Double = 1.4142135623730951
    
    scala> orig3d distanceTo unit3d
    res1: Double = 1.7320508075688772
    

    But not:

    scala> orig2d distanceTo unit3d
    <console>:15: error: type mismatch;
     found   : EuclideanPoint[shapeless.Nat._3]
     required: EuclideanPoint[shapeless.Nat._2]
                  orig2d distanceTo unit3d
                                    ^
    

    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.

    0 讨论(0)
  • 2021-01-02 03:48

    You could do something your self by doing a type level encoding of the Natural Numbers like: http://apocalisp.wordpress.com/2010/06/08/type-level-programming-in-scala/. Then just parametrizing your Vector by a Natural. Would not require the extra dependency, but would probably be more complicated then using Shapeless.

    0 讨论(0)
提交回复
热议问题