Skip to content

Instantly share code, notes, and snippets.

@danslapman
Last active September 26, 2018 06:34
Show Gist options
  • Save danslapman/90e7291c5f55047dbcf2dcac7b422344 to your computer and use it in GitHub Desktop.
Save danslapman/90e7291c5f55047dbcf2dcac7b422344 to your computer and use it in GitHub Desktop.
Combine two partial functions narrowing domain
import scala.util.{Success, Try}
val pf1: PartialFunction[Try[String], String] = {
case Success(s) => s
}
val pf2: PartialFunction[String, String] = {
case s if s.contains("pass") => s
}
class Combined[-A, B, +C] (pf: PartialFunction[A, B], k: PartialFunction[B, C]) extends PartialFunction[A, C] with Serializable {
import Combined._
def isDefinedAt(x: A) = {
val b: B = pf.applyOrElse(x, checkFallback[B])
if (!fallbackOccurred(b)) k.isDefinedAt(b) else false
}
def apply(x: A): C = k(pf(x))
override def applyOrElse[A1 <: A, B1 >: C](x: A1, default: A1 => B1) = {
val pfv = pf.applyOrElse(x, checkFallback[B])
if (!fallbackOccurred(pfv)) k.applyOrElse(pfv, (_: B) => default(x)) else default(x)
}
}
object Combined {
private[this] val fallback_pf: PartialFunction[Any, Any] = { case _ => fallback_pf }
private def checkFallback[B] = fallback_pf.asInstanceOf[PartialFunction[Any, B]]
private def fallbackOccurred[B](x: B) = fallback_pf eq x.asInstanceOf[AnyRef]
}
implicit class PartialFunctionCombine[A, B](pf: PartialFunction[A, B]) {
def combine[C](pf2: PartialFunction[B, C]): Combined[A, B, C] = new Combined(pf, pf2)
}
val pf = pf1 combine pf2
println(pf.applyOrElse(Try("reject"), (_: Try[String]) => "not defined"))
println(pf.applyOrElse(Try("pass"), (_: Try[String]) => "not defined"))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment