Skip to content

Instantly share code, notes, and snippets.

@logicalguess
Last active September 9, 2017 15:55
Show Gist options
  • Select an option

  • Save logicalguess/8ff8f0fd2204884101fbb73989aa46d9 to your computer and use it in GitHub Desktop.

Select an option

Save logicalguess/8ff8f0fd2204884101fbb73989aa46d9 to your computer and use it in GitHub Desktop.
combining functions into a PartialFunction
package logicalguess
import shapeless.HList._
import shapeless._
import scala.annotation.implicitNotFound
import scala.language.implicitConversions
import scala.reflect.ClassTag
object ShapelessFunctions {
// trait PfConverter[I, O, L <: HList] extends DepFn1[L] with Serializable {
// type Out = PartialFunction[I, O]
// }
trait PfConverter[I, O, L <: HList] extends Function1[L, PartialFunction[I, O]] with Serializable
implicit def pfConv1[H1, H2, T <: HList](implicit tailConv: PfConverter[Any, Any, T], tag: ClassTag[H1]): PfConverter[Any, Any, (H1 => H2) :: T] =
new PfConverter[Any, Any, (H1 => H2) :: T] {
def apply(l: (H1 => H2) :: T): PartialFunction[Any, Any] = {
val pf: PartialFunction[Any, Any] = {
case i: H1 =>
l.head(i)
}
pf.orElse(tailConv(l.tail))
}
}
implicit def emptyPfC[I, O]: PfConverter[I, O, HNil] =
new PfConverter[I, O, HNil] {
def apply(n: HNil) = Map.empty[I, O]
}
implicit def convertToPf[I, O, L <: HList](in: L)(implicit converter: PfConverter[I, O, L]) = converter(in)
@implicitNotFound("No function of type ''${I} => ${O}'' found in shape ${L}.")
trait ShapeWitness[L <: HList, I, O] extends Function2[L, I, O] with Serializable
// trait ShapeWitness[L <: HList, I, O] extends DepFn2[L, I] with Serializable {
// type In = I
// type Out = O
// }
object ShapeWitness {
implicit def witness[H1, H2, T <: HList]: ShapeWitness[(H1 => H2) :: T, H1, H2] =
new ShapeWitness[(H1 => H2) :: T, H1, H2] {
def apply(l: (H1 => H2) :: T, i: H1) = l.head(i)
}
implicit def recurse[H, T <: HList, I, O](implicit p: ShapeWitness[T, I, O]): ShapeWitness[H :: T, I, O] =
new ShapeWitness[H :: T, I, O] {
def apply(l: H :: T, i: I) = p(l.tail, i)
}
}
def apply[I, O, L <: HList](pf: PartialFunction[Any, Any], in: I)(implicit witness: ShapeWitness[L, I, O]): O = {
pf(in).asInstanceOf[O]
}
case class Input(value: String)
case class Output(value: String)
def main(args: Array[String]): Unit = {
// type L = (String => Int) :: (Input => Output) :: HNil
// val functionList: L = ((s: String) => s.length) :: ((c: Input) => Output(c.value)) :: HNil
// val pf: PartialFunction[Any, Any] = convertToPf(functionList)
val pf: PartialFunction[Any, Any] = ((s: String) => s.length) :: ((c: Input) => Output(c.value)) :: HNil
val res0: Output = apply(pf, Input("hi"))
println(res0 + ": " + res0.getClass)
// Output(hi): class logicalguess.ShapelessFunctions$Output
val res1 = pf(Input("hi"))
println(res1 + ": " + res1.getClass)
// Output(hi): class logicalguess.ShapelessFunctions$Output
val res2: Int = apply(pf, "abc")
println(res2 + ": " + res2.getClass)
// 3: int
val res3 = pf("abc")
println(res3 + ": " + res3.getClass)
// 3: class java.lang.Integer
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment