Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the relationship between PartialFunction and Function1

Tags:

scala

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!

like image 621
user6502167 Avatar asked Apr 24 '26 02:04

user6502167


1 Answers

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 
like image 186
HTNW Avatar answered Apr 25 '26 20:04

HTNW



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!