Реализовать curry(fn)
Реализуйте curry(fn), возвращающую каррированную версию fn. Она должна собирать аргументы по последовательным вызовам, пока не наберётся хотя бы fn.length аргументов, затем вызвать fn со всеми ними. Дано const add = (a, b, c) => a + b + c; каждая из форм curry(add)(1)(2)(3), curry(add)(1, 2)(3) и curry(add)(1, 2, 3) должна вернуть 6.
function curry(fn) {
// ваш код здесь
}
Допишите реализацию.
Вернуть рекурсивную curried(...args): если args.length >= fn.length, вызвать fn(...args); иначе вернуть новую функцию, принимающую ещё аргументы и вызывающую curried(...args, ...next), накапливая их в замыкании. fn.length (объявленная арность) — это порог, поэтому все формы частичного применения собирают аргументы, пока их не наберётся достаточно.
- ✗Жёстко задавать арность вместо чтения
fn.length - ✗Считать, что ровно один аргумент на вызов, ломая форму
(1, 2)(3) - ✗Делить один изменяемый массив аргументов между ветками, из-за чего частичные применения мешают друг другу
- →Почему
fn.length— верный порог, и когда он сообщает неверную арность? - →Как поддержать аргументы-заполнители, чтобы пропустить позицию параметра?
Решение
Рекурсивно накапливать аргументы, пока их число не достигнет объявленной арности fn.length.
function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) {
return fn.apply(this, args);
}
return (...next) => curried.apply(this, [...args, ...next]);
};
}
Как это работает
fn.length — объявленная арность функции (число её параметров). На каждом вызове curried сравнивает число собранных аргументов с этим порогом. Если их достаточно — вызывает fn со всеми аргументами. Иначе возвращает новую функцию, которая дождётся следующих аргументов и снова вызовет curried, объединив старые и новые через [...args, ...next].
Каждая ветка работает со своей копией массива аргументов, замкнутой в её вызове, поэтому формы (1)(2)(3), (1, 2)(3) и (1, 2, 3) независимы и все дают 6.