Если вы начинаете с функционального программирования и не знаете, что делать после 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
! Если, конечно, это предпочтительный способ на вашем языке.