Skip to content

Instantly share code, notes, and snippets.

@wheaties
Created October 19, 2016 13:01
Show Gist options
  • Select an option

  • Save wheaties/1c2fdc73241c213b84c67a579e262018 to your computer and use it in GitHub Desktop.

Select an option

Save wheaties/1c2fdc73241c213b84c67a579e262018 to your computer and use it in GitHub Desktop.
Shapeless Poly Compose Attempt
trait ComposeBuilder[F, G] extends DepFn2[F, G]
object ComposeBuilder extends LowPriorityComposeBuilder{
implicit def cc[C1 <: Poly, L1 <: HList, C2 <: Poly, L2 <: HList]
(implicit unpack1: Unpack1[C1, Compose1, L1],
unpack2: Unpack1[C2, Compose1, L2],
pre: hl.Prepend[L1, L2]): Aux[C1, C2, Compose1[pre.Out]] =
new ComposeBuilder[C1, C2]{
type Out = Compose1[pre.Out]
def apply(c1: C1, c2: C2) = new Compose1[pre.Out]
}
}
trait LowPriorityComposeBuilder extends LowPriorityComposeBuilder0{
implicit def cpoly[C <: Poly, L <: HList, G <: Poly]
(implicit unpack: Unpack1[C, Compose1, L],
pre: hl.Prepend[L, G :: HNil]): Aux[C, G, Compose1[pre.Out]] =
new ComposeBuilder[C, G]{
type Out = Compose1[pre.Out]
def apply(c: C, g: G) = new Compose1[pre.Out]
}
implicit def polyc[C <: Poly, L <: HList, F <: Poly]
(implicit unpack: Unpack1[C, Compose1, L]): Aux[F, C, Compose1[F :: L]] =
new ComposeBuilder[F, C]{
type Out = Compose1[F :: L]
def apply(f: F, c: C) = new Compose1[F :: L]
}
}
trait LowPriorityComposeBuilder0{
type Aux[F, G, Out1] = ComposeBuilder[F, G]{ type Out = Out1 }
implicit def polypoly[F <: Poly, G <: Poly]: Aux[F, G, Compose1[F :: G :: HNil]] =
new ComposeBuilder[F, G]{
type Out = Compose1[F :: G :: HNil]
def apply(f: F, g: G) = new Compose1[F :: G :: HNil] //new Compose1(f :: g :: HNil)
}
}
class Compose1[L] extends Poly
object Compose1{
implicit def comp[C, L <: HList, U](implicit unpack: Unpack1[C, Compose1, L], ev: ComposeWalk[L, U]): Case.Aux[C, U :: HNil, ev.Out] =
new Case[C, U :: HNil]{
type Result = ev.Out
val value = (u: U :: HNil) => ev(u.head)
}
}
trait ComposeWalk[L <: HList, U] extends DepFn1[U]
object ComposeWalk extends LowPriorityComposeWalk{
implicit def recur[H <: Poly, T <: HList, U, V](implicit ev: Case1.Aux[H, U, V], walk: ComposeWalk[T, V]):Aux[H :: T, U, walk.Out] =
new ComposeWalk[H :: T, U]{
type Out = walk.Out
def apply(u: U) = walk(ev(u))
}
}
trait LowPriorityComposeWalk{
type Aux[L <: HList, U, Out1] = ComposeWalk[L, U]{ type Out = Out1 }
implicit def hnil[U]: Aux[HNil, U, U] =
new ComposeWalk[HNil, U]{
type Out = U
def apply(u: U) = u
}
}
@Test
def testCompose1{
import PolyDefns._
//val yo = new Compose1(option :: isDefined :: HNil)
def yo[L <: HList, U](u: U)(implicit cw: ComposeWalk[L, U]): cw.Out = cw(u)
val out = yo[option.type :: isDefined.type :: HNil, Int](1)
assertEquals(true, out)
val out2 = yo[option.type :: isDefined.type :: option.type :: HNil, Int](1)
assertEquals(Option(true), out2)
val that = new Compose1[option.type :: isDefined.type :: HNil]
val out3 = that(1)
assertTypedEquals[Boolean](true, out3)
val those = new Compose1[option.type :: isDefined.type :: option.type :: HNil]
val out4 = those(1)
assertTypedEquals[Option[Boolean]](Option(true), out4)
val two = isDefined compose1 option
assertTypedEquals[Compose1[option.type :: isDefined.type :: HNil]](two, two)
val out5 = two(1)
assertTypedEquals[Boolean](true, out5)
//scuttled again.
//val three = option compose1 isDefined compose1 option
//assertTypedEquals[Compose1[option.type :: isDefined.type :: option.type :: HNil]](three, three)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment