2

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 ?

3 Answers 3

4

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 
Sign up to request clarification or add additional context in comments.

Comments

3

I don't see what got you confused about it? You just need to match-extract the Int out of A and then let the PF behave as it wants to behave.

scala> case class A(x: Int) // defined class A scala> val parf: PartialFunction[Int, String] = { case 0 => "!!!" } // parf: PartialFunction[Int,String] = <function1> scala> def foo(pf: PartialFunction[Int, String]): PartialFunction[A, String] = { | case A(x) if pf.isDefinedAt(x) => pf(x) | } // foo: (pf: PartialFunction[Int,String])PartialFunction[A,String] scala> val parfA = foo(parf) // parfA: PartialFunction[A,String] = <function1> scala> parfA(A(0)) //res0: String = !!! scala> parfA(A(1)) // scala.MatchError: A(1) (of class A) // at scala.PartialFunction$$anon$1.apply(PartialFunction.scala:254) // at scala.PartialFunction$$anon$1.apply(PartialFunction.scala:252) // at $anonfun$1.applyOrElse(<console>:11) // at $anonfun$1.applyOrElse(<console>:11) // at scala.runtime.AbstractPartialFunction.apply(AbstractPartialFunction.scala:34) // at $anonfun$foo$1.applyOrElse(<console>:13) // at $anonfun$foo$1.applyOrElse(<console>:13) // at scala.runtime.AbstractPartialFunction.apply(AbstractPartialFunction.scala:34) // ... 28 elided 

2 Comments

This will break behavior of isDefinedAt and lift on a new function
@OlegPyzhcov Yes. Great point. That is why - I don't see what got you confused about it?
1

@Oleg Pyzhcov already provided a great solution. Another approach would be to create a PartialFunction[A, Int] that is defined at A(0), and use andThen to chain it with parf:

val parf: PartialFunction[Int, String] = { case 0 => "!!!" } case class A(n: Int) val bar: PartialFunction[A, Int] = { case a: A if a.n == 0 => a.n } def foo(pf: PartialFunction[Int, String]): PartialFunction[A, String] = bar andThen pf // foo: (pf: PartialFunction[Int,String])PartialFunction[A,String] foo(parf) // res1: PartialFunction[A,String] = <function1> 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.