Skip to content

Instantly share code, notes, and snippets.

@Atry
Created March 3, 2017 07:15
Show Gist options
  • Save Atry/34282e9784a83b275ac7b91d2ff36a9b to your computer and use it in GitHub Desktop.
Save Atry/34282e9784a83b275ac7b91d2ff36a9b to your computer and use it in GitHub Desktop.
A universal type class that includes all shapeless.HList operations
import shapeless._
import shapeless.ops.hlist.ZipWithIndex.Helper
import shapeless.poly._
import shapeless.ops.hlist.{
Length,
LiftAll,
Mapper,
ToCoproduct,
ToList,
ZipWithIndex
}
/**
* @author 杨博 (Yang Bo) <[email protected]>
*/
trait HListWitness[L <: HList] {
type N <: Nat
def length: Length.Aux[L, N]
def toCoproduct: ToCoproduct[L]
def zipWithIndexHelper[Start <: Nat]: ZipWithIndex.Helper[L, Start]
def zipWithIndex: ZipWithIndex[L]
// def liftAll[F[_]]: LiftAll[F, L]
type Cases[HF <: Poly] <: HList
def map[HF <: Poly](cases: Cases[HF]): Mapper[HF, L]
def map[HF <: Poly](
implicit liftAll: LiftAll.Aux[Case1[HF, ?], L, Cases[HF]])
: Mapper[HF, L] = {
this.map[HF](liftAll.instances)
}
}
object HListWitness {
implicit object HNilWitness extends HListWitness[HNil] {
override def length = Length.hnilLength
override type N = _0
override def toCoproduct: ToCoproduct[HNil] = implicitly
override def zipWithIndexHelper[Start <: Nat] = Helper.hnil[Start]
override def zipWithIndex = ZipWithIndex.default(zipWithIndexHelper)
type Cases[HF <: Poly] = HNil
type MapResult[HF <: Poly, C <: Cases[HF]] = HNil
override def map[HF <: Poly](cases: Cases[HF]) = Mapper.hnilMapper1[HF]
}
trait HConsWitness[H, T <: HList] extends HListWitness[H :: T] {
val tailWitness: HListWitness[T]
override type N = Succ[tailWitness.N]
// OK
override def length = {
Length.hlistLength[H, T, tailWitness.N](tailWitness.length, implicitly)
}
// Can be type safe
override def toCoproduct: ToCoproduct[H :: T] = {
ToCoproduct.hlistToCoproduct(tailWitness.toCoproduct)
}
override def zipWithIndexHelper[Start <: Nat] = {
val tailHelper = tailWitness.zipWithIndexHelper[Succ[Start]]
Helper.hcons[H, T, tailHelper.Out, Start](tailHelper)
}
override def zipWithIndex = ZipWithIndex.default(zipWithIndexHelper)
override type Cases[HF <: Poly] = Case1[HF, H] :: tailWitness.Cases[HF]
// Require recursive typeof expression to be type safe, which is not support in Scala
override def map[HF <: Poly](cases: Cases[HF]) = {
Mapper.hlistMapper1[HF, H, T](cases.head, tailWitness.map(cases.tail))
}
}
implicit def hconWitness[H, T <: HList](
tailWitness0: HListWitness[T]): HConsWitness[H, T] {
val tailWitness: tailWitness0.type
} = {
new {
override val tailWitness: tailWitness0.type = tailWitness0
} with HConsWitness[H, T]
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment