Skip to content

Instantly share code, notes, and snippets.

@tomverran
Last active March 15, 2017 22:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tomverran/f3153911961c03c0610a0e3fc0d2a937 to your computer and use it in GitHub Desktop.
Save tomverran/f3153911961c03c0610a0e3fc0d2a937 to your computer and use it in GitHub Desktop.
A typeclass to recursively turn case classes into labelled nested HLists
import shapeless._
import shapeless.labelled._
trait DeepGeneric[T] {
type Repr <: HList
def to(t: T): Repr
}
trait LowPriority {
implicit def plainHconsDeepGeneric[H, T <: HList](
implicit
tl: DeepGeneric[T]
) = new DeepGeneric[H :: T] {
def to(t: H :: T): Repr = t.head :: tl.to(t.tail)
type Repr = H :: tl.Repr
}
}
object DeepGeneric extends LowPriority {
type Aux[A, R] = DeepGeneric[A] { type Repr = R }
def apply[A : DeepGeneric]: DeepGeneric[A] = implicitly[DeepGeneric[A]]
implicit val hnilDeepGeneric = new DeepGeneric[HNil] {
def to(a: HNil) = a
type Repr = HNil
}
implicit def nestedHconsDeepGeneric[K, H, T <: HList, RH <: HList, RT <: HList](
implicit
dg: Lazy[DeepGeneric.Aux[H, RH]],
tl: Lazy[DeepGeneric.Aux[T, RT]]
) = new DeepGeneric[FieldType[K, H] :: T] {
type Repr = FieldType[K, RH] :: RT
def to(t: FieldType[K, H] :: T): Repr = {
labelled.field[K](dg.value.to(t.head)) :: tl.value.to(t.tail)
}
}
implicit def genericDeepGeneric[A, R <: HList](
implicit
g: LabelledGeneric.Aux[A, R],
d: DeepGeneric[R]
) = new DeepGeneric[A] {
def to(a: A) = d.to(g.to(a))
type Repr = d.Repr
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment