Если вы начинаете с функционального программирования и не знаете, что делать после map и filter, переходите к reduce.

Reduce - это святой Грааль универсальности, когда дело касается обработки объектов и списков. Его свойства позволяют реализовать практически все:

- вы можете определить свою начальную стоимость

- вы управляете типом вывода

- проходит через все элементы

Это означает, что вы всегда можете контролировать, что входит внутрь, что выходит наружу и что находится внутри. Имея это в виду, вы можете выполнять любую чистую операцию, какую захотите, во время итерации, поскольку она по-прежнему вы контролируете вывод. Например, вот как реализовать filter с помощью reduce:

// JS
const filter = (fn, list) =>
  list.reduce((acc, next) => (fn(next) ? acc.concat(next) : acc), []);
// Haskell
filter’ :: (a -> Bool) -> [a] -> [a]
filter’ fn = foldr (\x xs -> if fn x then x:xs else xs) []

То же самое можно сделать и для map:

// JS
const map = (fn, list) =>
  list.reduce((acc, next) => acc.concat(fn(next)), []);
// Haskell
map’ :: (a -> b) -> [a] -> [b]
map’ fn = foldr (\x xs -> fn x : xs) []

Имейте в виду, что reduce может создавать любой тип значения, поэтому вы можете выполнять итерации, требующие запоминания некоторого промежуточного значения. Например, если мы хотим выбрать строки, помещенные между двумя другими строками, у нас может быть объект {output: «», inbetween: false}. Потом:

  • если inbetween, а не конечная строка, объединить с output
  • если inbetweenи конечная строка, вернуть output и установить inbetween на ложь
  • если не inbetween и начальная строка, установите для inbetween значение true
  • если не inbetween и не начальная строка, просто верните аккумулятор

Просто возьмите свойство output, когда закончите, и все готово.

Так что в следующий раз, когда вы захотите использовать цикл for, используйте вместо него reduce! Если, конечно, это предпочтительный способ на вашем языке.