I was trying to compose three functions with only the middle one being a PartialFunction. I would expect the resulting type to be PartialFunction as well.
Example:
val mod10: Int => Int = _ % 10
val inverse: PartialFunction[Int, Double] = { case n if n != 0 => 1.0 / n }
val triple: Double => Double = _ * 3
val calc: Int => Double = mod10 andThen inverse andThen triple
However, calc
is not defined on the whole of its domain. It will throw MatchError for every number divisible by 10.
What is the reason for returning a total function when at least one of the functions in the composition is partial?
Another example where composition of partial functions results in another partial function with incorrect domain conditions:
val inverse: PartialFunction[Double, Double] = { case n if n != 0 => 1.0 / n }
val arcSin: PartialFunction[Double, Double] = {
case n if math.abs(n) <= 1 => math.asin(n)
}
val calc: PartialFunction[Double, Double] = inverse andThen arcSin
I would expect the domain of calc
to be (-Infinity, -1] union [1, Infinity)
but calling calc.lift(0.5)
will throw a MathError instead of returning None
because the input is within the first function's domain.
Thanks, Norbert
It's because the first function in your first example is a total function (Function1) and its andThen method returns a Function1 regardless of whether the second function is total or partial:
My guess is that the Scala language design team prefers a more generalized returned value since PartialFunction is a subclass of Function and would rather let users derive specialized code as needed.
From the PartialFunction API doc, composing two partial functions via
andThen
will return a partial function with the same domain as the first partial function:Thus, the resultant composed function disregards the fact that
inverse(0.5)
(i.e. 2.0) is outside the domain of the second partial functionarcSin
.So, when composing a function (total or partial) with a partial function using
andThen
, how can we make it return a partial function with proper domain?Similar to what's demonstrated in this SO Q&A, one can enhance
andThen
via a couple of implicit classes to restrict the domain of the resultant composed function to a subset of the first function's domain that return values within the partial function's domain:Testing with the example functions: