Description
This is inspired by #5495 .
Should we allow implicit
on enum
case
s? As @milessabin has stated, we could use an enum as a shapeless Poly
with implicit cases corresponding to the Case
's of the Poly
.
For example, we have the following typelevel function that computes the index of a type in an HList
:
trait IndexOf[A, U] extends DepFn0 {
type Out <: Nat
def toInt: Int
}
object IndexOf {
def apply[A, U](implicit o: IndexOf[A, U]): Aux[A, U, o.Out] = o
type Aux[A, U, I <: Nat] = IndexOf[A, U] { type Out = I }
implicit def case0[At <: HList, U]: Aux[U :: At, U, _0] =
new IndexOf[U :: At, U] {
type Out = _0
def apply() = Nat._0
def toInt = 0
}
implicit def caseN[At <: HList, Ah, U, I <: Nat]
(implicit p: IndexOf.Aux[At, U, I]): Aux[Ah :: At, U, Succ[I]] =
new IndexOf[Ah :: At, U] {
type Out = Succ[I]
def apply() = Succ[I]()
def toInt = p.toInt + 1
}
}
This is quite verbose. Using implicit case
s, I hope that this could be simplified to something like this:
enum IndexOf[A, U] extends DepFn0 {
type Out <: Nat
def toInt: Int
implicit case Case0[At <: HList, U] extends IndexOf[U :: At, U] {
type Out = _0
def apply() = Nat._0
def toInt = 0
}
implicit case CaseN[At <: HList, Ah, U, I <: Nat]
(implicit p: IndexOf.Aux[At, U, I]) extends IndexOf[Ah :: At, U] {
type Out = Succ[I]
def apply() = Succ[I]()
def toInt = p.toInt + 1
}
}
where each implicit case
corresponds to a clause (as in programming in Prolog).
When desugaring, each case
is turned into a class in the enum
. Since implicit class
in Scala is treated as a class and an implicit def
(that converts an element to the implicit class wrapper), we could desugar each implicit case
into a class and an implicit def
. For example, the above could be desugared as:
enum IndexOf[A, U] extends DepFn0 {
type Out <: Nat
def toInt: Int
class Case0[At <: HList, U] extends IndexOf[U :: At, U] {
type Out = _0
def apply() = Nat._0
def toInt = 0
}
class CaseN[At <: HList, Ah, U, I <: Nat]
(implicit p: IndexOf.Aux[At, U, I]) extends IndexOf[Ah :: At, U] {
type Out = Succ[I]
def apply() = Succ[I]()
def toInt = p.toInt + 1
}
}
object IndexOf {
implicit def Case0$[At <: HList, U]: Case0[At, U] = new Case0()
implicit def CaseN$[At <: HList, Ah, U, I <: Nat](implicit p: IndexOf.Aux[At, U, I]): CaseN[Ah :: At, U, Succ[I]] = new CaseN()
}
Or I wonder what match-types would enable us in this situation?