Skip to content

Commit

Permalink
Merge pull request #701 from mgzuber/topic/NestedPairs
Browse files Browse the repository at this point in the history
Conversions between nested pairs and HLists
  • Loading branch information
joroKr21 authored Mar 18, 2020
2 parents 3cfe552 + 3ca0948 commit 0495f42
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 0 deletions.
53 changes: 53 additions & 0 deletions core/src/main/scala/shapeless/ops/hlists.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3068,4 +3068,57 @@ object hlist {
def apply(l: HNil): Out = HNil
}
}

/**
* Type class supporting mappings from type `T` to an `HList`. Currently only supports mapping nested pairs to an `HList`
*
* @author Michael Zuber
*/
sealed trait ProductToHList[-T] extends Serializable {
type Out <: HList
def apply(t: T): Out
}

object ProductToHList {
def apply[P](implicit ev: ProductToHList[P]): ProductToHList[P] = ev

type Aux[P, HL <: HList] = ProductToHList[P] { type Out = HL }

implicit def pairToHCons[H, T, HL <: HList](
implicit ev: ProductToHList.Aux[T, HL]
): ProductToHList.Aux[Product2[H, T], H :: HL] = new ProductToHList[Product2[H, T]] {
type Out = H :: HL
def apply(p: Product2[H, T]): Out = p._1 :: ev(p._2)
}

implicit val unitToHNil: ProductToHList.Aux[Unit, HNil] = new ProductToHList[Unit] {
type Out = HNil
def apply(p: Unit): Out = HNil
}
}

/**
* Type class supporting mappings from an `HList` to a nested pair
*
* @author Michael Zuber
*/
sealed trait HListToProduct[HL <: HList] extends DepFn1[HL] with Serializable

object HListToProduct {
def apply[HL <: HList](implicit ev: HListToProduct[HL]): HListToProduct[HL] = ev

type Aux[HL <: HList, P] = HListToProduct[HL] { type Out = P }

implicit val hnilToUnit: HListToProduct.Aux[HNil, Unit] = new HListToProduct[HNil] {
type Out = Unit
def apply(hl: HNil): Out = ()
}

implicit def hconsToPair[H, T <: HList, TP](
implicit ev: HListToProduct.Aux[T, TP]
): HListToProduct.Aux[H :: T, (H, TP)] = new HListToProduct[H :: T] {
type Out = (H, TP)
def apply(hl: H :: T): Out = (hl.head, ev(hl.tail))
}
}
}
5 changes: 5 additions & 0 deletions core/src/main/scala/shapeless/syntax/hlists.scala
Original file line number Diff line number Diff line change
Expand Up @@ -744,4 +744,9 @@ final class HListOps[L <: HList](l : L) extends Serializable {
* Returns all combinations of exactly length `N` of elements from this `Hlist`
*/
def combinations(n: Nat)(implicit combinations: Combinations[n.N, L]): combinations.Out = combinations(l)

/**
* Converts this `HList` into a nested pair
*/
def toProduct(implicit hListToProduct: HListToProduct[L]): hListToProduct.Out = hListToProduct(l)
}
7 changes: 7 additions & 0 deletions core/src/main/scala/shapeless/syntax/std/tuples.scala
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ package shapeless
package syntax
package std

import shapeless.ops.hlist.ProductToHList

trait LowPriorityTuple {
implicit def productTupleOps[P <: Product](p: P): TupleOps[P] = new TupleOps(p)
}
Expand Down Expand Up @@ -520,4 +522,9 @@ final class TupleOps[T](t: T) extends Serializable {
* both `HList`s have elements of the same types.
*/
def align[U](u: U)(implicit align: Align[T, U]): U = align(t)

/**
* Converts this nested `Product` into an `HList`
*/
def toHList(implicit productToHList: ProductToHList[T]): productToHList.Out = productToHList(t)
}
13 changes: 13 additions & 0 deletions core/src/test/scala/shapeless/hlist.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3484,4 +3484,17 @@ class HListTests {
@Test
def testIsHCons = assertTypedEquals[Int :: HNil](23 :: HNil, IsHCons[Int :: HNil].cons(23, HNil))

@Test
def testToProduct = {
val isbd = 2 :: "abc" :: true :: 3.0 :: HNil
val p = (2, ("abc", (true, (3.0, ()))))

import syntax.std.tuple._
assertEquals(isbd.toProduct, p)
assertEquals(p.toHList, isbd)
assertEquals(isbd.toProduct.toHList, isbd)
assertEquals(p.toHList.toProduct, p)
assertEquals((), (HNil: HNil).toProduct)
assertEquals(HNil, ().toHList)
}
}
Empty file added ~/.ivy2/.sbt.ivy.lock
Empty file.

0 comments on commit 0495f42

Please # to comment.