Обычно я понимаю каррирование и то, как оно использует замыкания:
function foo(a) {
return function(b) {
return function(c) {
return a*b*c;
}
}
}
как бы это было максимизировано? Разве это не сэкономило бы рабочее время, если бы ожидалось получение множества одних и тех же аргументов?
Например, если бы вы знали, что 5
всегда будет первым аргументом:
let first = foo(5);
тогда вы можете сделать:
first(8)(12);
или что-то еще для последних 2 аргументов.
Однако, если вы не ожидаете одних и тех же аргументов и каждый раз используете их следующим образом:
foo(3)(5)(9)
;
разве это не противоречит цели и не является ли это тем же самым, что и создание обычной функции, которая принимает только 3 аргумента?
Я просто пытаюсь понять вариант использования этого, потому что в моей голове это кажется действительно ограниченным.
В идеале вы должны использовать автокаррирование, чтобы вы могли использовать функцию любым способом, например f(a, b)(c)
, и все это должно работать одинаково. См. Например, Лодаш curry
.
Это полезно при частичном применении или сочинении. Вы можете сделать что-то вроде этого, например
const arr = [1,2,3,4]
const curry = (fn, ...a) => fn.length > a.length ? (...b) => curry(fn,...a.concat(b)) : fn.apply(null,a)
const add = curry((a,b) => a+b)
console.info(arr.map(add(5)))
const compose = (...fns) => fns.reduce((f,g) => b => f(g(b)))
console.info(arr.map(compose(add(5),add(2))))
Однако напрашивается вопрос, не так ли? «Случаи частичного применения»
Вариант без каррирования будет: arr.reduce((a, b) => a + b)
...
Вот несколько реальных примеров, где я использую это все время. Во-первых, на переднем конце:
debounce(someEventHandler, someTimeout);
debounce(someOtherEventHandler, someTimeout);
debounce(yetAnotherEventHandler, someTimeout);
Допустим, я хочу, чтобы все мои обработчики клавиатуры отключались на 250 мс. Я могу писать это снова и снова, или...
const debounceBy250 = curry(flip(debounce))(250);
Теперь код стал лаконичнее и понятнее. Во-вторых, на бэкэнде допустим, что у вас есть код, который получает тайм-аут запроса (база данных, REST, TCP, что угодно) из переменной окружения. Как и выше, вы можете либо добавить это везде, где он используется, либо частично применить его к функциям, которые его используют.
Для случая, когда кто-то на самом деле использовал его, но не знал, как он называется, см. мой ответ здесь на этот не совсем повторяющийся вопрос.
Ну, иногда это имеет смысл, когда вы создаете вспомогательные функции для создания обратных вызовов для других функций, например.
array.sort( sortBy("name") )
. Однако во многих случаях имеет смысл иметь одну функцию с несколькими параметрами. Так что вы правы, это очень ограничено.