I am handrolling my database API and would essentially like to model column families as a HList
of columns, with the latter loosely being a Seq[_]
, so somewhere I have a type like Column[String]::Column[Int]::Column[Double]::HNil
, with all elements sharing a common type constructor.
What would be the simplest way of expressing the type of rows, ie String::Int::Double::HNil
, from the type given above, essentially unwrapping the inner types?
My current reasoning is that since shapeless can do a map over that HList
given the right poly
, one should be able to (ab)use the depedent type Out
of the Mapper
trait.
One thing I can think of is just implementing a useless poly
with the right cases, like a Case.Aux[Column[T],T]
for all T
s then summon a Mapper
for it et voilá, there I have my Out
, but this feels a bit hacky and I'm not sure it would even work.
On the other hand, I do not yet feel that comfortable around dependent types and type recursion to really want to try and implement something which shapeless obviously already does.
Thank you for any input!
Try
import shapeless.PolyDefns.~>
import shapeless.ops.hlist.{Comapped, NatTRel}
import shapeless.{HList, HNil, Id}
object App {
case class Column[A](a: A)
def extract[L <: HList, L1 <: HList](l: L)(implicit
comapped: Comapped.Aux[L, Column, L1],
natTRel: NatTRel[L, Column, L1, Id],
): L1 = natTRel.map(new (Column ~> Id) { def apply[T](col: Column[T]) = col.a }, l)
val result = extract(Column(1) :: Column("a") :: HNil)
def main(args: Array[String]): Unit = {
println(result) // 1 :: a :: HNil
}
}
or
import shapeless.PolyDefns.~>
import shapeless.ops.hlist.NatTRel
import shapeless.{HList, HNil}
object App {
case class Column[A](a: Seq[A])
def extract[L <: HList, L1 <: HList](l: L)(implicit
natTRel: NatTRel[L, Column, L1, Seq],
): L1 = natTRel.map(new (Column ~> Seq) { def apply[T](col: Column[T]): Seq[T] = col.a }, l)
val result = extract(Column(Seq("a", "b")) :: Column(Seq(1, 2)) :: Column(Seq(10.0, 20.0)) :: HNil)
def main(args: Array[String]): Unit = {
println(result) // List(a, b) :: List(1, 2) :: List(10.0, 20.0) :: HNil
}
}