Loda sh рекурсивная функция превышает максимальный размер стека - PullRequest
1 голос
/ 04 марта 2020

Цель

Я пытаюсь создать функцию "deepMapValues". Он возьмет такую ​​функцию, как ...

(v, k) => k == 'hello' ? 'world' : v;
// if the key is 'hello' then return the value 'world' else return the value that already exists there.

И объект, подобный ...

{
  hello: true,
  foo: {
    hello: 'bar'
  }
}

И вернет объект ..

{
  hello: 'world',
  foo: {
    hello: 'world'
  }
}

Использование это так ... deepMap(mapFunction)(inputObject)

Моя текущая функция

Я написал эту маленькую функцию, используя loda sh ...

const mapValuesWithKey = _.mapValues.convert({ 'cap': false });
// this is because I want both the value and key passed into the map function

deepMap = fn => mapValuesWithKey(
  _.cond([
    [_.isArray, _.map(deepMap(fn))],
    [_.isPlainObject, deepMap(fn)],
    [_.T, fn],
  ])
);

Когда я ее запускаю Я немедленно получаю cra sh ...

RangeError: Превышен максимальный размер стека вызовов

Что можно ожидать, так как функция рекурсивна и, если не выполнена, правильно он будет бесконечно повторяться.

Однако я изменил его на это (только для тестирования) ...

deepMap = fn => mapValuesWithKey(
  _.cond([
    [_.T, fn],
  ])
);

И это сработало (что снова ожидается).

Но когда я изменил его на это ...

deepMap = fn => mapValuesWithKey(
  _.cond([
    [_.T, fn],
    [_.F, deepMap(fn)],
  ])
);

Он снова упал с той же ошибкой. Несмотря на то, что рекурсия НИКОГДА не произойдет в приведенном выше коде, она все еще превышает размер стека вызовов.

Используя код loda sh из Github, я подозревал, что перед выполнением команды он может оценить все пары в _.cond код, поэтому я написал свою собственную версию cond.

const myCond = pairs => {
  return (...args) => {
    for (const pair of pairs) {
      if (pair[0](args)) {
        return pair[1](args)
      }
    }
  }
};

Но это также все еще сбой.

Я не уверен, что я делаю здесь неправильно, как кажется быть рекурсивным, даже если для него не может быть рекурсии?

Что я делаю не так?

Спасибо

Rubber Duck EDIT

Я думаю, что это может быть потому, что функция оценивается с помощью параметра fn, а затем создает объект в паре cond, которая повторяется с fn, который делает то же самое снова и снова и снова ...

Расследование.

Дополнительный вопрос

Если приведенное выше верно ... как я могу остановить ошибку, но все же передать fn через рекурсия?

1 Ответ

0 голосов
/ 04 марта 2020

Хорошо, я понял, когда подошел к концу написания вопроса. Рекурсия происходит не при оценке функций с переданным объектом, а при создании пар условий в первую очередь.

Я обновил код до этого ...

deepMap = fn => _.mapValues(
  _.cond([
    [_.isArray, _.map(o => deepMap(fn)(o))],
    [_.isPlainObject, o => deepMap(fn)(o)],
    [_.T, fn],
  ])
);

Это отсортировал это. Теперь он не передает fn в глубокую карту до тех пор, пока условие не будет оценено и функция не будет запущена.

...