Skip to content

Instantly share code, notes, and snippets.

@i10416
Created December 23, 2021 06:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save i10416/46e41cea6331e65fa66ef8df1c0abf1b to your computer and use it in GitHub Desktop.
Save i10416/46e41cea6331e65fa66ef8df1c0abf1b to your computer and use it in GitHub Desktop.
generic vector representation using shapeless
import $ivy.`com.chuusai::shapeless:2.3.7`
import shapeless._
trait VecLike[T]{
def dim:Int
def add(a:T,b:T):T
def sub(a:T,b:T):T
}
implicit def doubleVec2D:VecLike[(Double,Double)] =
new VecLike[(Double,Double)] {
def dim:Int = 2
def add(a:(Double,Double),b:(Double,Double)):(Double,Double) = (a._1+b._1,a._2+b._2)
def sub(a:(Double,Double),b:(Double,Double)):(Double,Double) = (a._1 - b._1, a._2 - b._2)
}
implicit class VecLikeOps[T:VecLike](underlying:T) {
def dim:Int = implicitly[VecLike[T]].dim
def |+|(b:T) :T = implicitly[VecLike[T]].add(underlying,b)
def |-|(b:T):T = implicitly[VecLike[T]].sub(underlying,b)
}
implicit def numericVec2D[T:Numeric]:VecLike[(T,T)] =
new VecLike[(T,T)] {
def dim:Int = 2
def add(a:(T,T),b:(T,T)):(T,T) = (Numeric[T].plus(a._1,b._1),Numeric[T].plus(a._2,b._2))
def sub(a:(T,T),b:(T,T)):(T,T) = (Numeric[T].minus(a._1,b._1),Numeric[T].minus(a._2,b._2))
}
trait GenericVecLike[L<: HList] extends VecLike[L] {type Elm}
object GenericVecLike {
type Aux[L<:HList,A] = GenericVecLike[L]{ type Elm = A}
implicit def empty[A]:Aux[HNil,A] = new GenericVecLike[HNil] {
type Elm = A
def dim = 0
def add(a:HNil,b:HNil):HNil = HNil
def sub(a:HNil,b:HNil):HNil = HNil
}
implicit def cons[T<:HList,A:Numeric](implicit tail:Aux[T,A]):Aux[A::T,A] = new GenericVecLike[A::T] {
type Elm = A
def dim: Int = tail.dim + 1
def add(a: A :: T, b: A :: T): A :: T = Numeric[A].plus(a.head,b.head) :: tail.add(a.tail,b.tail)
def sub(a: A :: T, b: A :: T): A :: T = Numeric[A].minus(a.head,b.head) :: tail.sub(a.tail,b.tail)
}
}
implicit def genericVec[T,Repr <: HList](implicit gen:Generic.Aux[T,Repr],instance:GenericVecLike[Repr]):VecLike[T] = new VecLike[T] {
def dim: Int = instance.dim
def add(a: T, b: T): T = gen.from(instance.add(gen.to(a),gen.to(b)))
def sub(a: T, b: T): T = gen.from(instance.sub(gen.to(a),gen.to(b)))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment