Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala Partial Function Type Definition

val even: PartialFunction[Int, String] = PartialFunction[Int, String] {
  case i if i % 2 == 0 => i + " is even"
}

val isEven: PartialFunction[Int, String] = {
  case i if i % 2 == 0 => i + " is even"
}

val odd: PartialFunction[Int, String] = PartialFunction[Int, String] {
  case x if x % 2 == 1 => x + " is odd"
}


val isOdd: PartialFunction[Int, String] = {
  case x if x % 2 == 1 => x + " is odd"
}

val tot = even orElse odd
val tot2 = isEven orElse isOdd

println(tot(3))
println(tot2(3))

In this code tot function throws match error while tot2 function works as expected. Only difference between them is the way they're defined. Can anyone explain why such difference in result?

Thanks in advance!!!

like image 449
pramesh Avatar asked May 03 '18 03:05

pramesh


People also ask

How do you define a partial function in Scala?

// Creating Partial function1. val M : PartialFunction[Int, Int] = { // using case statement. case x if (x % 5 ) == 0 => x * 5.

What is partial function example?

Another example of a partial function is given by y = x + 1 x2 − 3x + 2 , assuming that both the input and output domains are R. This partial function “blows up” for x = 1 and x = 2, its value is “infinity” (= ∞), which is not an element of R. So, the domain of f is R − {1,2}.

Can a partial function be Injective?

Many properties of functions can be extended in an appropriate sense of partial functions. A partial function is said to be injective, surjective, or bijective when the function given by the restriction of the partial function to its domain of definition is injective, surjective, bijective respectively.

What is higher order functions in Scala?

In Scala, a higher-order function is a function which takes another function as an argument. A higher-order function describes "how" the work is to be done in a collection. Let's learn the higher order function map. The map applies the function to each value in the collection and returns a new collection.


2 Answers

At the core the difference is that isDefinedAt on the partial function is not being defined as you would expect on the version using the PartialFunction.apply method. That is actually why this method is now deprecated, PartialFunction.apply is meant to convert a total function into a partial function with isDefinedAt always returning true, which means it will think it is defined for 3 in your example, and try to apply the function instead of falling back to the even function you have supplied as an alternative.

This brings up a common sore point in the community regarding total functions vs partial functions. PartialFunction is a subtype of Function, I guess in the OO design sense that it is a function with an additional method (isDefinedAt) which tells you whether the function is defined for a particular value. Many feel this is a mistake, as in the Liskov sense, Function should be a subtype of PartialFunction because you can use a Function anywhere a PartialFunction is expected, but if you use a PartialFunction where a Function is expected it will compile, then may fail at runtime. My feeling is that it is because Function can be considered to have an implicit isDefinedAt that always returns true, which would allow you to correct the relationship and make Function a subtype of PartialFunction. This comes to a head in PartialFunction.apply which expects a total function and due to this expectation defines isDefinedAt to always return true, but it can’t enforce that expectation, so if you call PartialFunction.apply(somePartialFunction) bad things happen that most programmers won’t expect.

PartialFunction.apply Scaladoc

PartialFunction[Int, String]{...} is syntactic sugar for
PartialFunction[Int, String].apply({...})

To minimize:

val even: PartialFunction[Int, String] = PartialFunction[Int, String]{
  case i if i % 2 == 0 => i + " is even"
}

val isEven: PartialFunction[Int, String] = {
  case i if i % 2 == 0 => i + " is even"
}

println(even.isDefinedAt(3)) //true
println(isEven.isDefinedAt(3)) //false
like image 140
Shane Delmore Avatar answered Sep 22 '22 01:09

Shane Delmore


In the first two cases you are calling the apply function in the companion object of PartialFunction. I know, that sounds as if it should work. But it doesn't because PartialFunction.apply should read PartialFunction.fromTotalFunction.

This is a scala language issue and, if I remember correctly (can't find the ticket at the moment, will look later), this apply function will be gone and replaced by fromTotalFunction in Scala 2.13.

UPDATE

The ticket I meant was #6005

It seems that PartialFunction.apply is already deprecated since Scala 2.12.5.

like image 32
Sascha Kolberg Avatar answered Sep 19 '22 01:09

Sascha Kolberg