I'm trying to do the following:
val divide: PartialFunction[(Int, Int), Int] = {
case (x, y) if (y != 0) => x / y
}
val divide42 = (y: Int) => divide((42, y))
However:
divide42.isDefinedAt(0)
cmd18.sc:1: value isDefinedAt is not a member of Int => Int
val res18 = divide42.isDefinedAt(0)
^Compilation Failed
What is the right way to preserve PartialFunction
functionality when going from PartialFunction
to partially applied function?
CodePudding user response:
You can use compose
to preserve the partial nature:
val divide: PartialFunction[(Int, Int), Int] = {
case (x, y) if (y != 0) => x / y
}
val divide42: PartialFunction[Int, Int] = divide.compose {
case y: Int => (42, y)
}
divide42.isDefinedAt(0) // false
What you wrote doesn't work because it's actually syntactic sugar for the following:
val divide42 = new Function1[Int, Int] {
def apply(y: Int) = divide((42, y))
}
The call to divide
inside divide42
is an expression that evaluates to Int
(or throw). There is no way to preserve the fact that divide
is a partial function with this syntax.
Or explicitly write a new partial function like this but more verbose:
val divide: PartialFunction[(Int, Int), Int] = {
case (x, y) if (y != 0) => x / y
}
val divide42: PartialFunction[Int, Int] = {
case (y: Int) if divide.isDefinedAt((42, y)) => divide((42, y))
}
divide42.isDefinedAt(0) // false
CodePudding user response:
Help the compiler help you, define your types explicitly:
EDIT: I realized that simply changing the types results in the y != 0
part of the function not working as intended. compose
addresses this as already mentioned in another answer (which is correct).
val divide: PartialFunction[(Int, Int), Int] = {
case (x, y) if y != 0 => x / y
}
// OLD: val divide42: PartialFunction[Int, Int] = (y: Int) => divide((42, y))
// |- Returns true for `isDefinedAt(0)` which is WRONG!!
// |- If someone could explain why this happens (???), please comment :)
val divide42: PartialFunction[Int, Int] = (y: Int) => divide.compose {
case y: Int => (42, y)
}
divide42.isDefinedAt(0) // False
When you define it as you have, the compiler changes the type of divide42
to Int => Int
as opposed to PartialFunction[Int, Int]
:
// Implicit type, `Int => Int`
val divide42 = (y: Int) => divide((42, y))
// `isDefinedAt` is not defined for `Int => Int`
divide42.isDefinedAt(0) // !! Error !!
CodePudding user response:
The following seem right to me:
val divide: PartialFunction[(Int, Int), Int] = {
case (x, y) if (y != 0) => x / y
}
val divide42: PartialFunction[Int, Int] = {
case x if (x != 0) => divide(42, x)
}
divide42.isDefinedAt(0) // false
divide42(6) // 7
This both follows the correct definition pattern for PartialFunction
and suits the definition of a partially applied function