Skip to content

Instantly share code, notes, and snippets.

@jkodumal
Created September 22, 2012 16:57
Show Gist options
  • Save jkodumal/3766759 to your computer and use it in GitHub Desktop.
Save jkodumal/3766759 to your computer and use it in GitHub Desktop.
Type-safe transformation from nested case classes to HLists using shapeless
// Based on shapeless 1.2.2
import shapeless._, HList._
trait RecIso[T, R] {
def iso(t: T) : R
}
trait RecId[T] extends RecIso[T, T] {
def iso(t: T) : T = t
}
implicit object intRecIso extends RecId[Int]
implicit object stringRecIso extends RecId[String]
implicit object longRecIso extends RecId[Long]
implicit object hnilRecIso extends RecId[HNil]
// Recursively transform any hlist
implicit def hlRecIso[D, T <: HList, R, S <: HList](implicit dri: RecIso[D, R], lri : RecIso[T, S]) = new RecIso[D :: T, R :: S] {
def iso(a: D :: T): R :: S = dri.iso(a.head) :: lri.iso(a.tail)
}
// Recursively transform a case class with an isomorphism into an hlist
implicit def ccRecIso[C <: Product, L <: HList, R <: HList](implicit is: HListIso[C, L], hlri: RecIso[L, R]) = new RecIso[C, R] {
import HListIso._
def iso(c: C) = hlri.iso(toHList(c))
}
def makeIso[T, R](d: T)(implicit dri: RecIso[T, R]): R = dri.iso(d)
// A pair of arbitrary case classes, one nested
case class Foo(i : Int, s : String)
case class Bar(s : String, f: Foo)
// Publish their `HListIso`'s
implicit def fooIso = HListIso(Foo.apply _, Foo.unapply _)
implicit def barIso = HListIso(Bar.apply _, Bar.unapply _)
type FooHList = Int :: String :: HNil
type BarHList = String :: FooHList :: HNil
val foo = Foo(1, "foo")
val bar = Bar("bar", foo)
// Yields a FooHList
makeIso(foo)
// Yields a BarHList
makeIso[Bar, BarHList](bar) // you have to help out scala's type inference in this case
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment