I was playing with scalaz and thought I could extend Enum type class for something to make myself understand scalaz better. So I wrote this:
sealed abstract trait Counter
case object First extends Counter
case object Second extends Counter
case object Third extends Counter
implicit val enumCounter: Enum[Counter] = new Enum[Counter] {
override def succ(a: Counter): Counter = a match {
case First => Second
case Second => Third
case Third => First
}
override def pred(a: Counter): Counter = a match {
case First => Third
case Second => First
case Third => Second
}
override def order(x: Counter, y: Counter): Ordering = {
val map = Map[Counter, Int](First -> 0, Second -> 1, Third -> 2)
implicitly[Order[Int]].order(map(x), map(y))
}
}
println(First |=> Third)
println(First.succ)
But it turns out that it doesn't work as I hoped it will. First does not have succ nor |=>, because I've created Enum[Counter] but not Enum[First]. If I write First.asInstanceOf[Counter].succ it starts to resolve. Which is now obvious to me. But how can I implement Enum typeclass then in a simple way? I do not want to declare separate implicit values for each of Enum[First], Enum[Second]....
There are two possible solutions I am thinking of:
1) Make scala resolve Enum[First] as Enum[Counter]. But I cannot seem to understand how this can be possible as Enum can be only nonvariant
2) Maybe there is a solution in scalaz?
Otherwise Enum typeclass starts to be quite limited, as it does not supports Enum which sounds very weird.
I am actually not sure how much this question belongs to scalaz, it probably depends on whether the solution is (1) or (2). If the solution is (1) - this question is pure scala.