Частичная функция - это функция, которая действительна только для подмножества значений тех типов, которые вы можете передать ей. Например:
val root: PartialFunction[Double,Double] = {
case d if (d >= 0) => math.sqrt(d)
}
scala> root.isDefinedAt(-1)
res0: Boolean = false
scala> root(3)
res1: Double = 1.7320508075688772
Это полезно, когда у вас есть что-то, что знает, как проверить, определена функция или нет. Соберите, например:
scala> List(0.5, -0.2, 4).collect(root) // List of _only roots which are defined_
res2: List[Double] = List(0.7071067811865476, 2.0)
Это , а не поможет вам разместить два аргумента там, где вы действительно хотите один.
Напротив, частично примененная функция - это функция, в которой некоторые ее аргументы уже заполнены.
def add(i: Int, j: Int) = i + j
val add5 = add(_: Int,5)
Теперь вам нужен только один аргумент - вещь, к которой нужно добавить 5 - вместо двух:
scala> add5(2)
res3: Int = 7
Из этого примера видно, как его использовать.
Но если вам нужно указать эти два аргумента, этот все равно этого не сделает - скажем, вы хотите использовать, например, map
, и вам нужно дать ему функцию одного аргумент, но вы хотите добавить две разные вещи. Ну, тогда вы можете
val addTupled = (add _).tupled
, который будет частично применять функцию (на самом деле, просто создать функцию из метода, поскольку ничего не было заполнено), а затем объединить отдельные аргументы в кортеж. Теперь вы можете использовать это в местах, где требуется один аргумент (при условии, что тип правильный):
scala> List((1,2), (4,5), (3,8)).map(addTupled)
res4: List[Int] = List(3, 9, 11)
Напротив, карри снова отличается; он превращает функции вида (A,B) => C
в A => B => C
. То есть, учитывая функцию с несколькими аргументами, она создаст цепочку функций, каждая из которых принимает один аргумент и возвращает цепочку на один короче (вы можете думать о ней как о частичном применении одного аргумента за раз).
val addCurried = (add _).curried
scala> List(1,4,3).map(addCurried)
res5: List[Int => Int] = List(<function1>, <function1>, <function1>)
scala> res5.head(2) // is the first function, should add 1
res6: Int = 3
scala> res5.tail.head(5) // Second function should add 4
res7: Int = 9
scala> res5.last(8) // Third function should add 3
res8: Int = 11