Permalink
Browse files

Generalized HListIso to an isomorphism between arbitrary types.

  • Loading branch information...
1 parent 9781d46 commit 902047b54fd045ef8a63fafccd7b78b307b4659f @milessabin committed May 20, 2012
@@ -19,29 +19,45 @@ package shapeless
/**
* Representation of an isomorphism between a type (typically a case class) and an `HList`.
*/
-class HListIso[T, L <: HList](ctor : L => T, dtor : T => L) {
- def fromHList(l : L) : T = ctor(l)
- def toHList(t : T) : L = dtor(t)
+trait Iso[T, U] {
+ def to(t : T) : U
+ def from(u : U) : T
}
-object HListIso {
+object Iso {
import Functions._
import Tuples._
- def apply[CC, C, T <: Product, L <: HList](apply : C, unapply : CC => Option[T])
+ def hlist[CC, C, T <: Product, L <: HList](apply : C, unapply : CC => Option[T])
(implicit fhl : FnHListerAux[C, L => CC], hl : HListerAux[T, L]) =
- new HListIso(apply.hlisted, (cc : CC) => hl(unapply(cc).get))
+ new Iso[CC, L] {
+ val ctor = apply.hlisted
+ val dtor = (cc : CC) => hl(unapply(cc).get)
+ def to(t : CC) : L = dtor(t)
+ def from(l : L) : CC = ctor(l)
+ }
// Special case for one-element cases classes because their unapply result types
// are Option[T] rather than Option[Tuple1[T]] which would be required to fit
// the general case.
- def apply[CC, T](apply : T => CC, unapply : CC => Option[T]) =
- new HListIso(apply.hlisted, (cc : CC) => unapply(cc).get :: HNil)
+ def hlist[CC, T](apply : T => CC, unapply : CC => Option[T]) =
+ new Iso[CC, T :: HNil] {
+ val ctor = apply.hlisted
+ val dtor = (cc : CC) => unapply(cc).get :: HNil
+ def to(t : CC) : T :: HNil = dtor(t)
+ def from(l : T :: HNil) : CC = ctor(l)
+ }
- def fromHList[T, L <: HList](l : L)(implicit iso : HListIso[T, L]) = iso.fromHList(l)
+ implicit def tupleHListIso[T <: Product, L <: HList](implicit hl : HListerAux[T, L], uhl : TuplerAux[L, T]) =
+ new Iso[T, L] {
+ val ctor = uhl.apply _
+ val dtor = hl.apply _
+ def to(t : T) : L = dtor(t)
+ def from(l : L) : T = ctor(l)
+ }
- def toHList[T, L <: HList](t : T)(implicit iso : HListIso[T, L]) = iso.toHList(t)
-
- implicit def tupleIso[T <: Product, L <: HList](implicit hl : HListerAux[T, L], uhl : TuplerAux[L, T]) =
- new HListIso(uhl.apply, hl.apply)
+ implicit def identityIso[T] = new Iso[T, T] {
+ def to(t : T) : T = t
+ def from(t : T) : T = t
+ }
}
@@ -27,12 +27,10 @@ trait Lens[C, F] {
def set(d : D)(f : F) : D = g.set(d)(outer.set(g.get(d))(f))
}
- def >>[L <: HList, N <: Nat](n : N)(implicit iso : HListIso[F, L], lens : HListNthLens[L, N]) =
+ def >>[L <: HList, N <: Nat](n : N)(implicit iso : Iso[F, L], lens : HListNthLens[L, N]) =
new Lens[C, lens.Elem] {
- import HListIso._
-
- def get(c : C) : lens.Elem = lens.get(toHList(outer.get(c)))
- def set(c : C)(f : lens.Elem) = outer.set(c)(fromHList(lens.set(toHList(outer.get(c)))(f)))
+ def get(c : C) : lens.Elem = lens.get(iso.to(outer.get(c)))
+ def set(c : C)(f : lens.Elem) = outer.set(c)(iso.from(lens.set(iso.to(outer.get(c)))(f)))
}
def ~[G](other : Lens[C, G]) = new ProductLens[C, (F, G)] {
@@ -78,9 +78,9 @@ trait LowPrioritySybClass {
/**
* Data type class instance for types with associated `HListIso`s.
*/
- implicit def hlistIsoData[F <: Poly, T, L <: HList, R](implicit iso : HListIso[T, L], dl : Data[F, L, R]) =
+ implicit def hlistIsoData[F <: Poly, T, L <: HList, R](implicit iso : Iso[T, L], dl : Data[F, L, R]) =
new Data[F, T, R] {
- def gmapQ(t : T) = dl.gmapQ(iso.toHList(t))
+ def gmapQ(t : T) = dl.gmapQ(iso.to(t))
}
/**
@@ -149,9 +149,9 @@ trait LowPrioritySybClass {
/**
* DataT type class instance for type with associated `HListIso`s.
*/
- implicit def hlistIsoDataT[F <: Poly, T, L <: HList](implicit iso : HListIso[T, L], dl : DataT[F, L]) =
+ implicit def hlistIsoDataT[F <: Poly, T, L <: HList](implicit iso : Iso[T, L], dl : DataT[F, L]) =
new DataT[F, T] {
- def gmapT(t : T) = iso.fromHList(dl.gmapT(iso.toHList(t)))
+ def gmapT(t : T) = iso.from(dl.gmapT(iso.to(t)))
}
/**
@@ -28,8 +28,8 @@ class LensTests {
case class Address(street : String, city : String, postcode : String)
case class Person(name : String, age : Int, address : Address)
- implicit val addressIso = HListIso(Address.apply _, Address.unapply _)
- implicit val personIso = HListIso(Person.apply _, Person.unapply _)
+ implicit val addressIso = Iso.hlist(Address.apply _, Address.unapply _)
+ implicit val personIso = Iso.hlist(Person.apply _, Person.unapply _)
val address = Address("Southover Street", "Brighton", "BN2 9UA")
val person = Person("Joe Grey", 37, address)
@@ -211,8 +211,8 @@ class SybClassTests {
case class Address(street : String, city : String, postcode : String)
case class Person(name : String, age : Int, address : Address)
- implicit val addressIso = HListIso(Address.apply _, Address.unapply _)
- implicit val personIso = HListIso(Person.apply _, Person.unapply _)
+ implicit val addressIso = Iso.hlist(Address.apply _, Address.unapply _)
+ implicit val personIso = Iso.hlist(Person.apply _, Person.unapply _)
@Test
def testHListIso {
@@ -33,8 +33,8 @@ object LenseExamples extends App {
case class Person(name : String, age : Int, address : Address)
// One line of boilerplate per case class ...
- implicit val addressIso = HListIso(Address.apply _, Address.unapply _)
- implicit val personIso = HListIso(Person.apply _, Person.unapply _)
+ implicit val addressIso = Iso.hlist(Address.apply _, Address.unapply _)
+ implicit val personIso = Iso.hlist(Person.apply _, Person.unapply _)
// Some lenses over Person/Address ...
val nameLens = Lens[Person] >> _0
@@ -24,19 +24,18 @@ object MonoidExamples extends App {
// Given an isomorphism between `C` and an `HList` `L`, construct a monoid instance for `C` given
// the monoid instance for `L`, which is in turn derived from the monoid instances for its/`C`'s
// element types.
- implicit def ccMonoid[C, L <: HList](implicit iso : HListIso[C, L], ml : Monoid[L]) = new Monoid[C] {
- import HListIso._
- def zero = fromHList(ml.zero)
- def append(a : C, b : C) = fromHList(toHList(a) |+| toHList(b))
+ implicit def ccMonoid[C, L <: HList](implicit iso : Iso[C, L], ml : Monoid[L]) = new Monoid[C] {
+ def zero = iso.from(ml.zero)
+ def append(a : C, b : C) = iso.from(iso.to(a) |+| iso.to(b))
}
// A pair of arbitrary case classes
case class Foo(i : Int, s : String)
case class Bar(b : Boolean, s : String, d : Double)
// Publish their `HListIso`'s
- implicit def fooIso = HListIso(Foo.apply _, Foo.unapply _)
- implicit def barIso = HListIso(Bar.apply _, Bar.unapply _)
+ implicit def fooIso = Iso.hlist(Foo.apply _, Foo.unapply _)
+ implicit def barIso = Iso.hlist(Bar.apply _, Bar.unapply _)
// And now they're monoids ...
@@ -38,11 +38,11 @@ object SybClassExamples extends App {
type Name = String
type Address = String
- implicit def companyIso[D <: HList] = HListIso(Company.apply[D] _, Company.unapply[D] _)
- implicit def deptIso[S <: HList] = HListIso(Dept.apply[S] _, Dept.unapply[S] _)
- implicit val employeeIso = HListIso(Employee.apply _, Employee.unapply _)
- implicit val personIso = HListIso(Person.apply _, Person.unapply _)
- implicit val salaryIso = HListIso(Salary.apply _, Salary.unapply _)
+ implicit def companyIso[D <: HList] = Iso.hlist(Company.apply[D] _, Company.unapply[D] _)
+ implicit def deptIso[S <: HList] = Iso.hlist(Dept.apply[S] _, Dept.unapply[S] _)
+ implicit val employeeIso = Iso.hlist(Employee.apply _, Employee.unapply _)
+ implicit val personIso = Iso.hlist(Person.apply _, Person.unapply _)
+ implicit val salaryIso = Iso.hlist(Salary.apply _, Salary.unapply _)
/*
// The HListIso definitions for each case class above replace this manually

0 comments on commit 902047b

Please sign in to comment.