Это забавная вещь в функциональном программировании, которая называется curry . По сути, Моисей Шенфинкель и последний Хаскелл Карри (Schonfinkeling звучит странно, хотя ...) пришли к мысли, что вызов функции с несколькими аргументами, скажем, f(x,y)
- это то же самое, что цепочка вызовов {g(x)}(y)
или g(x)(y)
, где g
- это функция, которая создает другую функцию в качестве своего выхода.
В качестве примера возьмем функцию f(x: Int, y: Int) = x + y
. Вызов f(2,3)
выдаст 5
, как и ожидалось. Но что происходит, когда мы каррируем эту функцию - переопределите ее как f(x:Int)(y: Int)
и назовите ее f(2)(3)
. Первый вызов f(2)
создает функцию, которая принимает целое число y
и добавляет к нему 2
-> поэтому f(2)
имеет тип Int => Int
и эквивалентна функции g(y) = 2 + y
. Второй вызов f(2)(3)
вызывает вновь созданную функцию g
с аргументом 3
, поэтому, как и ожидалось, оценивается в 5
.
Другой способ увидеть это - пошаговое сокращение (функциональные программисты называют это бета-редукцией - это как функциональный способ поэтапного перехода) вызова f(2)(3)
(обратите внимание, что на самом деле Scala не является действительным синтаксис).
f(2)(3) // Same as x => {y => x + y}
|
{y => 2 + y}(3) // The x in f gets replaced by 2
|
2 + 3 // The y gets replaced by 3
|
5
Итак, после всего этого разговора f(x)(y)
можно рассматривать как просто следующее лямбда-выражение (x: Int) => {(y: Int) => x + y}
- которое является действительным Scala.
Надеюсь, все это имеет смысл - я попытался дать немного фона , почему вызов modN(3)
имеет смысл:)