scalapartialfunction

How to convert one partial function to another?


Suppose I've got partial function parf

val parf: PartialFunction[Int, String] = { case 0 => "!!!" }

Now I've got also case class A(x: Int) and I need a function to transform PartialFunction[Int, String] to PartialFunction[A, String]:

def foo(pf: PartialFunction[Int, String]): PartialFunction[A, String] = ???

For example, foo(parf) should return {case A(0) => "!!!" }. How would you write function foo ?


Solution

  • To maintain the correct functionality, you need to check if the inner partial function is defined on a parameter you're going to pass:

    val parf: PartialFunction[Int, String] = { case 0 => "!!!" }
    
    case class A(x: Int)
    
    def foo(pf: PartialFunction[Int, String]): PartialFunction[A, String] = {
      case A(i) if pf.isDefinedAt(i) => pf(i)
    }
    

    If you plan to do it on a larger scale, you might want to convert a partial function to an extractor object, so it can be used in pattern matches directly with a better syntax:

    trait Extractor[A, B] {
      def unapply(a: A): Option[B]
    }
    
    object Extractor {
      implicit def partialFunctionAsExtractor[A, B](pf: PartialFunction[A, B]): Extractor[A, B] =
        new Extractor[A, B] {
          def unapply(a: A) = if (pf.isDefinedAt(a)) Some(pf(a)) else None
        }
    }
    
    def foo2(pf: Extractor[Int, String]): PartialFunction[A, String] = {
        case A(pf(str)) => str
    }
    
    foo2(parf) // implicit conversion magic