类型类:维护类型级别的值

时间:2017-10-21 22:59:25

标签: scala type-level-computation

我想创建一个Int值的类型级别表示,其存储方式如下:

sealed trait Position {
  def value : Int
}

class P1 extends Position {val value = 1}
class P2 extends Position {val value = 2} 

当一个班级扩展它时:

case class PExtended() extends P1

我想在类型级别检索值:

def getValue[A <: Position] = ???
getValue[PExtended] //should return 1

我尝试了一些方法,但不确定这是否是解决此问题的最佳方法。任何建议如何开始都会很棒。

2 个答案:

答案 0 :(得分:1)

您可以添加A

类型的值
def getValue[A <: Position](a: A): Int = a.value
println(getValue(new PExtended))//1

或使value成为一种类型

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

或者您可以使用隐含

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

我同意@YuvalItzchakov您可以查看shapeless.Nat

https://github.com/milessabin/shapeless/blob/master/core/src/main/scala/shapeless/nat.scala#L29-L49

例如

import shapeless.Nat
import shapeless.ops.nat.{Sum, ToInt}
import shapeless.Nat._

implicitly[Sum.Aux[_2, _3, _5]]//compiles

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

答案 1 :(得分:1)

您需要实现一个类型类并使用Shapeless Nat数来解决问题:

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

然后你可以用它来实现你的方法

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