#javascript #currying #pointfree
#javascript #каррирование #без точек
Вопрос:
В качестве игрушечного примера предположим, что у нас есть эта функция и ее использование:
const map = (f = n => n 1) => (lst = [1,2,3]) => {
if(lst.length === 0)
return [];
else
return [f(...lst.splice(0,1)), ...map(f)(lst)];
}
const inc = n => n 1;
const map_inc = map(inc);
map_inc([1,2,3]) // => (produces) [2,3,4]
Внутри карты функций curried я использую «рекурсию», вызывая map(f)(lst)
.
Приведенный выше пример перестраивает функцию перед ее вызовом.
Возможно ли выполнить эту рекурсию без перестройки функции?
Я знаю этот способ:
y = (f = (f, ...args) => [...args],
...args) => f(f, ...args);
const map = (mapper = n => n 1) => (self = mapper, lst = [1,2,3]) => {
if(lst.length === 0)
return [];
else
return [mapper(...lst.splice(0,1)), ...self(self, lst)];
}
const inc = n => n 1;
const map_inc = (...args) => y(map(inc), ...args);
map_inc([1,2,3]) // => (produces) [2,3,4]
Мне не очень нравится, как это требует передачи функции самой себе.
Можно ли это сделать без y
функции и без передачи функции самой себе? Можно ли это сделать в более свободном от точек стиле?
Комментарии:
1. Из-за ваших имен переменных очень сложно определить, что вы пытаетесь сделать. (Хотя я не тот, кто проголосовал против)
2.
Uncaught ReferenceError: _ is not defined
3. @NinoFiliu это может быть, а может и не быть Lodash
_.split()
. Я понятия не имею, пока этот вопрос не будет улучшен.4. Что вы подразумеваете под перестройкой функции ?
5. @NinoFiliu Он имеет в виду повторный вызов
reducer
, чтобы получить новый экземпляр функции, которую она возвращает.
Ответ №1:
Если я правильно понимаю ваш вопрос, вы не можете возвращать именованные функции со стрелками, но вы можете вернуть именованную обычную функцию и вызвать ее рекурсивно следующим образом:
const reducer = k => function recurse(a, item) {
//...
const s_res = _.split(item, k, 1);
return recurse(a.withMutations(a => {
a.push(s_res[0]);
let a_element = document.createElement('a');
a_element.setAttribute('href', '#');
a_element.addEventListener('click', () => display_gen_element(k, obj));
a.push(a_element);
}), s_res[1]);
};
P.S. Для удобства чтения, пожалуйста, не используйте однобуквенные имена переменных, если только не очевидно, для чего они предназначены, например, для счетчика в for
цикле и т.д.
Ответ №2:
Если вашей целью было устранить необходимость передавать self самому себе
...self(self, lst)
Вы можете сделать это, добавив еще 1 функцию с именем recursor
const map = (mapper = n => n 1) => (lst = [1, 2, 3]) => {
const recursor = lst => {
if (lst.length === 0) return [];
else return [mapper(...lst.splice(0, 1)), ...recursor(lst)];
};
return recursor(lst);
};
const inc = n => n 1;
const map_inc = map(inc);
console.log(map_inc([1, 2, 3])); // => (produces) [2,3,4]
Вам вообще не нужна была вызываемая функция, подобная y combinator y
.
recursor
имеет mapper
в своем закрытии