Рекурсивный вызов каррированной функции в Javascript

#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 в своем закрытии