Ответ 1
Надеюсь, вы не против, если я начну с примера Haskell, так как Haskell - это гораздо более простой язык, чем Scala. В Haskell все функции являются функциями в математическом смысле - они принимают один аргумент и возвращают одно значение. Haskell также имеет кортежи, и вы можете написать функцию, которая немного похожа на несколько параметров, как функцию от кортежа до любого. Например:
Prelude> let add = (\(x, y) -> x + y) :: (Int, Int) -> Int
Prelude> add (1, 2)
3
Теперь мы можем выполнить эту функцию для получения функции с типом Int -> Int -> Int
вместо (Int, Int) -> Int
:
Prelude> let curriedAdd = curry add
Это позволяет частично применить функцию, например:
Prelude> let add3 = curriedAdd 3
Prelude> add3 1
4
Итак, у нас есть чистое чистое определение currying - это функция, которая принимает функцию с кортежем (в частности, пару) для аргумента и возвращает функцию, которая принимает в качестве аргумента первый тип в паре и возвращает функцию от второго типа в паре до исходного типа возврата. Это всего лишь многообещающий способ сказать следующее:
Prelude> :t curry
curry :: ((a, b) -> c) -> a -> b -> c
Хорошо, теперь для Scala.
В Scala вы также можете иметь функции, которые принимают аргумент кортежа. Scala также имеет "функции", которые принимают более одного аргумента (Function2
и выше). Это (путано) разные виды животных.
Scala также имеет методы, которые отличаются от функций (хотя они могут быть преобразованы в функции более или менее автоматически через eta-расширение). Методы могут иметь несколько параметров, или параметры кортежа, или несколько списков параметров.
Итак, что значит сказать, что мы что-то понимаем в этом контексте?
В буквальном смысле, currying - это то, что вы делаете с Function2
(и вверх):
scala> val add: Function2[Int, Int, Int] = (x: Int, y: Int) => x + y
add: (Int, Int) => Int = <function2>
scala> val curriedAdd = add.curried
curriedAdd: Int => (Int => Int) = <function1>
scala> val add3 = curriedAdd(3)
add3: Int => Int = <function1>
Это примерно то же, что мы видели в случае Haskell, за исключением того, что мы просматриваем функцию с несколькими аргументами, что не так хорошо существует в Haskell.
Теперь я уверен, что это единственный контекст, в котором слово curry действительно появляется в стандартной библиотеке Scala (не считая сопровождающего uncurried
на Function
сопутствующий объект), но учитывая огромный беспорядок, который Scala делает из идеи методов, функций и т.д. (не поймите меня неправильно - я люблю Scala, но это часть языка - это полная катастрофа), мне представляется разумным применить слово в следующем контексте:
def add(x: Int, y: Int) = x + y
def curriedAdd(x: Int)(y: Int) = add(x, y)
Здесь мы превратили метод, который принимает два параметра в метод с несколькими списками параметров, каждый из которых принимает только один параметр (эта последняя часть важна).
И на самом деле спецификация языка также использует этот термин в этом контексте, описывая следующее как "определение одной, кардной функции" :
def func(x: Int)
(y: Int) = x + y
(Это, конечно, сбивает с толку как ад, так как это метод, а не функция.)
Итак, чтобы подвести итог: несколько списков параметров являются одним из способов реализации currying в Scala, но не все методы с несколькими списками параметров являются только для curries, где каждый список параметров имеет единственный параметр. И вся терминология довольно мягкая, так или иначе, так что не беспокойтесь о том, чтобы правильно это понять.