Если вам интересно углубиться в теорию, я предлагаю вам прочитать кое-что о катаморфизмах , анаморфизмах и хиломорфизмах . Хотя теория категорий, которая ее окружает, может показаться немного пугающей, концепция не так уж сложна.
Катаморфизмы - это функции, которые потребляют рекурсивные структуры данных и выдают какое-то значение. Анаморфизмы - это функции, которым дано некоторое значение (своего рода начальное число) , создающее рекурсивные структуры данных. В частности, foldr
и build
, упомянутые в других ответах, являются функциями для построения катаморфизмов и анаморфизмов в списках. Но эта концепция может быть применена в основном к любой рекурсивной структуре данных, такой как различные виды деревьев и т. Д.
Теперь, если вы строите рекурсивную структуру данных с анаморфизмом, а затем используете ее с катаморфизмом, вы получите то, что называется гиломорфизмом. В таком случае вам на самом деле не нужна промежуточная структура. Вы можете пропустить его создание и уничтожение. Это часто называют вырубка леса .
Относительно map
: эта функция интересна тем, что является одновременно катаморфизмом и анаморфизмом:
map
потребляет список и производит что-то; но также
map
создает список, потребляющий что-то.
Таким образом, вы можете рассматривать композицию из двух карт map f . map g
как композицию анаморфизма (map g
) с катаморфизмом (map f
), образующего гиломорфизм. Таким образом, вы можете оптимизировать (вырубить), не создавая промежуточный список.
Если быть точным: вы могли бы написать map
двумя способами, один используя foldr
, а другой используя build
:
mapAna :: (a -> b) -> [a] -> [b]
mapAna f xs = build (mapAna' f xs)
mapAna' :: (a -> b) -> [a] -> (b -> c -> c) -> c -> c
mapAna' f [] cons nil = nil
mapAna' f (x : xs) cons nil = (f x) `cons` (mapAna' f xs cons nil)
mapCata :: (a -> b) -> [a] -> [b]
mapCata f xs = foldr (\x ys -> f x : ys) [] xs
и состав map f (map g zs)
как mapCata f (mapAna g zs)
, что после некоторых упрощений и применения foldr c n (build g) == g c n
приводит к map (f . g)
.