I'm learning Scala, and find from scala doc the definition of PartialFunction and Function1, as shown below:
trait PartialFunction[-A, +B] extends (A) ⇒ B
trait Function1[-T1, +R] extends AnyRef
Q1) My 1st question is: what's the type of (A) => B?
And, I know we can turn the PartialFunction to be a normal function by the lift method.
But Q2) what's the relationship between ParitialFunction and Function1?
It seems if some function parameter is of type Function1, we can pass a matching PartitionFunction to it, as shown below:
scala> val process = (f: Function1[String, Int]) => f("1024")
process: (String => Int) => Int = <function1>
scala> val pattern = "([0-9]+)".r
pattern: scala.util.matching.Regex = ([0-9]+)
scala> val str2int: PartialFunction[String, Int] = {
| case pattern(num) => num.toInt
| }
str2int: PartialFunction[String,Int] = <function1>
scala> accept(str2int)
res67: Int = 1024
Thanks!
A ⇒ B is syntax sugar for Function1[A, B]. Similarly, (A1, A2) ⇒ R is actually Function2[A1, A2, R], etc. all the way to 22 (completely arbitrary limit). The definition of PartialFunction is thus
trait PartialFunction[-A, +B] extends Function1[A, B]
Since a PartialFunction[A, B] is also a Function1[A, B], you can pass it into something that wants an A ⇒ B. The only reason we use ⇒ over FunctionN is aesthetic: it looks nicer. Indeed, since ⇒ isn't really a type name, we can't say something like:
type ApIntInt[T[_, _]] = T[Int, Int]
// ApIntInt[⇒] // Error: ⇒ is not a type and was not expected here
ApIntInt[Function1] // Fine: Function1 is a type, it has the right kind, so it works.
// ApIntInt[Function1] = Function1[Int, Int] = Int ⇒ Int
Since you're a beginner, you won't see this kind of stuff (higher kinds) for a long time yet, but it is there, and you may well hit it someday.
When you use a PartialFunction as a Function1, if you pass a value at which it is not defined, it (probably) throws an exception, which is usually a MatchError (but doesn't have to be). By contrast, if you call pf.lift, that creates a Function[In, Option[Out]], which returns Some(result) if the PartialFunction is defined at a point, and returns None if it isn't, per the Scaladoc.
Ex:
lazy val factorial: PartialFunction[Int, Int] = {
case num if num > 1 => num * factorial(num - 1)
case 1 => 1
}
assert(!factorial.isDefinedAt(0))
factorial.apply(0) // Using a PF as a Function1 on an undefined point breaks (here with MatchError)
factorial.lift.apply(0) // This just returns None, because it checks isDefinedAt first
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With