Reputation: 5210
I would like to create a type level representation of an Int
value stored something like this:
sealed trait Position {
def value : Int
}
class P1 extends Position {val value = 1}
class P2 extends Position {val value = 2}
And when a class extends it:
case class PExtended() extends P1
I would like to retrieve the value at type level:
def getValue[A <: Position] = ???
getValue[PExtended] //should return 1
I have tried a few things, but not sure if this is the best way to solve this problem. Any suggestion how to get started would be great.
Upvotes: 3
Views: 133
Reputation: 3863
You need to implement a type class and use Shapeless Nat numbers to solve the problem:
import shapeless.ops.nat.ToInt
import shapeless.Nat
import shapeless.ops.nat.ToInt
trait Number[A] {
def number: Int
}
object Number {
def apply[A](implicit number: Number[A]): Number[A] = number
implicit def positionNumber[A, N <: Nat](implicit eq: A <:< Position[N], toInt: ToInt[N]): Number[A] = {
new Number[A] {
override def number: Int = toInt.apply()
}
}
}
Then you can use it to implement your method
sealed trait Position[T <: Nat]
class P1 extends Position[Nat._1]
class P2 extends Position[Nat._2]
object Test extends App {
case class PExtended() extends P1
def getValue[A](implicit number: Number[A]): Int = {
number.number
}
println(getValue[PExtended])
}
Upvotes: 1
Reputation: 51658
You can either add value of type A
def getValue[A <: Position](a: A): Int = a.value
println(getValue(new PExtended))//1
or make value
a type
type One
type Two
sealed trait Position1 {
type Value
}
class P11 extends Position1 { override type Value = One }
class P21 extends Position1 { override type Value = Two }
implicitly[P11#Value =:= P11#Value]//compiles
implicitly[P11#Value =:= P21#Value]//doesn't compile
Or you can use implicits
implicit val p1: P1 = new P1
implicit val p2: P2 = new P2
def getValue[A <: Position](implicit a: A): Int = a.value
println(getValue[P1])//1
println(getValue[P2])//2
I agree with @YuvalItzchakov that you can look at shapeless.Nat
https://github.com/milessabin/shapeless/blob/master/core/src/main/scala/shapeless/nat.scala#L29-L49
For example
import shapeless.Nat
import shapeless.ops.nat.{Sum, ToInt}
import shapeless.Nat._
implicitly[Sum.Aux[_2, _3, _5]]//compiles
or
def calculateSum[N <: Nat, M <: Nat,
NplusM <: Nat](n: N, m: M)(implicit
sum: Sum.Aux[N, M, NplusM],
toInt: ToInt[NplusM]): Int = toInt()
println(calculateSum(_2, _3)) // 5
Upvotes: 1