We continue the journey on Scala on the topic of Partial Functions in this post. For
all the work in this post, we will use Read-Evaluate-Print-Loop
Scala interpreter. Some familiarity
with Java will be of great help in understanding Scala.
To understand the concept of Partial Functions, let us take a List as an example. We have discussed Lists in an earlier post. Let us define a List as shown below:
val List1 = List.range(-3, 3)
Let us compute the square roots of a few elements:
Math.sqrt(List1(0))
Math.sqrt(List1(5))
The results are shown below:
scala> val List1 = List.range(-3,3)
List1: List[Int] = List(-3, -2, -1, 0, 1, 2)
scala> Math.sqrt(List1(0))
res9: Double = NaN
scala> Math.sqrt(List1(5))
res10: Double = 1.4142135623730951
We can also apply the map function as shown below:
List1 map ( x => Math.sqrt(x))
The results are shown below:
scala> List1 map ( x => Math.sqrt(x))
res31: List[Double] = List(NaN, NaN, NaN, 0.0, 1.0, 1.4142135623730951)
We see that some of the value are NaN that we would like to give a miss. So, here comes the Partial Functions that can be applied only to a set of values that we desire.
val root = new PartialFunction[Int, Double] {
def apply(x: Int) = Math.sqrt(x)
def isDefinedAt(x: Int) = (x >= 0)
}
The code just means that root takes an integer and returns a double of the square root as defined in the apply function, but, subject to the condition that isDefinedAt evaluates to true. It is more like the program shown below:
if (root.isDefinedAt(1)) root.apply(1)
The results are shown below:
scala> if (root.isDefinedAt(1)) root.apply(1)
res18: AnyVal = 1.0
If we pass any value less than zero, the results are as below:
scala> if (root.isDefinedAt(-1)) root.apply(-1)
res19: AnyVal = ()
Let us see first apply the square root function to our List using map:
scala> List1 map root
res32: List[Double] = List(NaN, NaN, NaN, 0.0, 1.0, 1.4142135623730951)
The above results are the same as that returned by List1 map ( x => Math.sqrt(x)). The difference is when we use collect method as shown below:
scala> List1 collect root
res33: List[Double] = List(0.0, 1.0, 1.4142135623730951)
Now, we see that the conditional defined by isDefinedAt is used and we do not see any NaNs. This functionality of Partial Functions can be used as a guard to prevent exceptions by filtering out potential elements that may give rise to exceptions. After seeing collect, we can look at collectFirst that returns the first element that satisfies the condition after application of partial function (not obvious here) as shown below:
scala> List1 collectFirst root
res47: Option[Double] = Some(0.0)
This concludes the discussion on Partial Functions in Scala
To understand the concept of Partial Functions, let us take a List as an example. We have discussed Lists in an earlier post. Let us define a List as shown below:
val List1 = List.range(-3, 3)
Let us compute the square roots of a few elements:
Math.sqrt(List1(0))
Math.sqrt(List1(5))
The results are shown below:
scala> val List1 = List.range(-3,3)
List1: List[Int] = List(-3, -2, -1, 0, 1, 2)
scala> Math.sqrt(List1(0))
res9: Double = NaN
scala> Math.sqrt(List1(5))
res10: Double = 1.4142135623730951
We can also apply the map function as shown below:
List1 map ( x => Math.sqrt(x))
The results are shown below:
scala> List1 map ( x => Math.sqrt(x))
res31: List[Double] = List(NaN, NaN, NaN, 0.0, 1.0, 1.4142135623730951)
We see that some of the value are NaN that we would like to give a miss. So, here comes the Partial Functions that can be applied only to a set of values that we desire.
val root = new PartialFunction[Int, Double] {
def apply(x: Int) = Math.sqrt(x)
def isDefinedAt(x: Int) = (x >= 0)
}
The code just means that root takes an integer and returns a double of the square root as defined in the apply function, but, subject to the condition that isDefinedAt evaluates to true. It is more like the program shown below:
if (root.isDefinedAt(1)) root.apply(1)
The results are shown below:
scala> if (root.isDefinedAt(1)) root.apply(1)
res18: AnyVal = 1.0
If we pass any value less than zero, the results are as below:
scala> if (root.isDefinedAt(-1)) root.apply(-1)
res19: AnyVal = ()
Let us see first apply the square root function to our List using map:
scala> List1 map root
res32: List[Double] = List(NaN, NaN, NaN, 0.0, 1.0, 1.4142135623730951)
The above results are the same as that returned by List1 map ( x => Math.sqrt(x)). The difference is when we use collect method as shown below:
scala> List1 collect root
res33: List[Double] = List(0.0, 1.0, 1.4142135623730951)
Now, we see that the conditional defined by isDefinedAt is used and we do not see any NaNs. This functionality of Partial Functions can be used as a guard to prevent exceptions by filtering out potential elements that may give rise to exceptions. After seeing collect, we can look at collectFirst that returns the first element that satisfies the condition after application of partial function (not obvious here) as shown below:
scala> List1 collectFirst root
res47: Option[Double] = Some(0.0)
This concludes the discussion on Partial Functions in Scala