I am trying to use an HList as implemented here. I was hoping to be able to traverse this structure using inline functions to do some simple compile time “code generation”.
I can do this this using the following code (see all of the code in scastie):
inline def split[L <: Tup](left:L): List[String] =
inline left match
case _: EmpT.type => List("Empty")
case cons: TCons[_, _] =>
"NonEmpty" :: split(cons.tail)
However, this only works if I explicitly type the “HList”:
val m4 = split(1+:EmpT: TCons[Int,EmpT.type])
println(m4)
val tup5: 5 +: 6 +: EmpT.type = 5 +: 6 +: EmpT
val m5 = split(tup5)
println(m5)
However, this won’t work:
val tup6 = TCons(5, TCons(6, Tup.EmpT))
val m6 = split(tup6)
println(m6)
It fails with:
cannot reduce inline match with
scrutinee: data.Data2.tup6 : (data.Data2.tup6 : data.Data2.Tup)
patterns : case _:data.Data2.Tup#EmpT.type
case cons @ _:data.Data2.Tup.TCons[_ @ >: Nothing <: Any, _ @ >: Nothing <: Any]
So my question is, how can one retain all of the types without having to explicitly type each element of the HList?
As per the link provided in the discussion of the issue above, this is documented:
“Generally, the type of a enum case constructor application will
be widened to the underlying enum type, unless a more specific
type is expected. This is a subtle difference with respect to
normal case classes. The classes making up the cases do exist,
and can be unveiled, either by constructing them directly with
a new, or by explicitly providing an expected type.”