Skip to content

Instantly share code, notes, and snippets.

@milessabin
Last active August 29, 2015 14:23
Show Gist options
  • Select an option

  • Save milessabin/4de2145c55375f92388f to your computer and use it in GitHub Desktop.

Select an option

Save milessabin/4de2145c55375f92388f to your computer and use it in GitHub Desktop.
import shapeless._
import shapeless.ops.hlist.Tupler
trait Evaluator[L <: HList] {
type Out <: HList
def apply(value:String, l:L):Option[Out]
}
object Evaluator {
type JExt[T] = String => Option[T]
type Aux[T <: HList, O <: HList] = Evaluator[T]{ type Out = O }
implicit val evaluatorHNil:Aux[HNil, HNil] = new Evaluator[HNil] {
type Out = HNil
def apply(value:String, l:HNil) = Some(HNil)
}
implicit def evalHCons[H, T <: HList](implicit evalT: Evaluator[T]): Aux[JExt[H] :: T, H :: evalT.Out] =
new Evaluator[JExt[H] :: T] {
type Out = H :: evalT.Out
def apply(value:String, l: JExt[H] :: T):Option[Out] =
for {
h <- l.head(value)
t <- evalT(value, l.tail)
} yield h :: t
}
}
object ExtractorCompositor {
def join[L <: HList, O <: HList, T](maybes: L)(implicit ev: Evaluator.Aux[L, O], tpl:Tupler.Aux[O, T]) =
new ExtractComposite(maybes, ev, tpl)
def testFails[L <: HList, T <: HList](value:String, maybes: L)(implicit ev: Evaluator.Aux[L, T]):Option[T] =
ev.apply(value, maybes)
def testSuccess[L <: HList, T <: HList](value:String, maybes: L)(implicit ev: Evaluator[L]) =
ev.apply(value, maybes)
class ExtractComposite[L <: HList, O <: HList, T](maybes: L, ev: Evaluator.Aux[L, O], tpl:Tupler.Aux[O, T]) {
def unapply(value:String):Option[T] = {
ev.apply(value, maybes).map{hl =>
tpl.apply(hl)
}
}
}
}
object ShapelessTest {
import Evaluator._
import ExtractorCompositor._
import ops.hlist.Tupler._
def main(args:Array[String]) {
val s = "Hello world"
val hList = ((s: String) => s.headOption) :: ((s: String) => Option(s.length)) :: HNil
println(testSuccess(s, hList)) //Works
println(testFails(s, hList)) //Failed
val composite = join(hList) //Desired result
s match {
case composite(head, length) =>
println(s"first char $head with length $length")
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment