Data.Foldable
| Авторские права | Ross Paterson 2005 |
|---|---|
| Лицензия | BSD-стиль (см. файл LICENSE в дистрибутиве) |
| Поддержка | libraries@haskell.org |
| Стабильность | стабильная |
| Портируемость | портативная |
| Safe Haskell | Safe |
| Язык | Haskell2010 |
Содержание
Описание
Класс структур данных, которые могут быть свернуты в значение сводки.
class Foldable (t :: Type -> Type) where Исходный код
Класс Foldable представляет структуры данных, которые могут быть сведены к значению сводки по одному элементу за раз. Строгие свертки слева направо хорошо подходят для эффективного сокращения, а ленивые свертки справа налево хорошо подходят для корекурсивной итерации или для сверток, которые прерываются после обработки начальной подпоследовательности элементов структуры.
Экземпляры могут быть автоматически получены путём включения расширения DeriveFoldable. Например, полученный экземпляр для бинарного дерева может быть:
{-# LANGUAGE DeriveFoldable #-}
data Tree a = Empty
| Leaf a
| Node (Tree a) a (Tree a)
deriving Foldable
Более подробное описание можно найти в разделе Обзор в Data.Foldable.
Законы класса см. в разделе Законы в Data.Foldable.
Методы
fold :: Моноид m => t m -> m Источник
Учитывая структуру с элементами, тип которых является Monoid, объединить их с помощью оператора (<>) моноида. Этот fold является правоассоциативным и ленивым в накопителе. Если вам нужен строгий левоассоциативный fold, используйте foldMap' вместо него, с id в качестве отображения.
Примеры
Базовое использование:
>>> fold [[1, 2, 3], [4, 5], [6], []] [1,2,3,4,5,6]
>>> fold $ Node (Leaf (Sum 1)) (Sum 3) (Leaf (Sum 5))
Sum {getSum = 9}
Склады в неограниченных структурах не завершаются, когда оператор моноида (<>) является строгим:
>>> fold (repeat Nothing) * Hangs forever *
Ленивые рекурсивные folds неограниченных структур в порядке:
>>> take 12 $ fold $ map (\i -> [i..i+2]) [0..] [0,1,2,1,2,3,2,3,4,3,4,5] >>> sum $ take 4000000 $ fold $ map (\i -> [i..i+2]) [0..] 2666668666666
foldMap :: Моноид m => (a -> m) -> t a -> m Источник
Преобразовать каждый элемент структуры в моноид и объединить результаты с помощью (<>). Этот fold является правоассоциативным и ленивым в накопителе. Для строгих левоассоциативных folds рассмотрите foldMap' вместо этого.
Примеры
Базовое использование:
>>> foldMap Sum [1, 3, 5]
Sum {getSum = 9}
>>> foldMap Product [1, 3, 5]
Product {getProduct = 15}
>>> foldMap (replicate 3) [1, 2, 3] [1,1,1,2,2,2,3,3,3]
Когда оператор (<>) моноида является ленивым в своем втором аргументе, foldMap может вернуть результат даже из неограниченной структуры. Например, ленивое накопление позволяет Data.ByteString.Builder эффективно сериализовать большие структуры данных и поэтапно генерировать вывод:
>>> import qualified Data.ByteString.Lazy as L >>> import qualified Data.ByteString.Builder as B >>> let bld :: Int -> B.Builder; bld i = B.intDec i <> B.word8 0x20 >>> let lbs = B.toLazyByteString $ foldMap bld [0..] >>> L.take 64 lbs "0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24"
foldMap' :: Моноид m => (a -> m) -> t a -> m Источник
Левоассоциативная разновидность foldMap , которая является строгой в накопителе. Используйте этот метод для строгого сокращения, когда частичные результаты объединяются с помощью (<>).
Примеры
Определите Monoid над конечными двоичными строками в xor. Используйте его для строгого вычисления xor списка Int значений.
>>> :set -XGeneralizedNewtypeDeriving >>> import Data.Bits (Bits, FiniteBits, xor, zeroBits) >>> import Data.Foldable (foldMap') >>> import Numeric (showHex) >>> >>> newtype X a = X a deriving (Eq, Bounded, Enum, Bits, FiniteBits) >>> instance Bits a => Semigroup (X a) where X a <> X b = X (a `xor` b) >>> instance Bits a => Monoid (X a) where mempty = X zeroBits >>> >>> let bits :: [Int]; bits = [0xcafe, 0xfeed, 0xdeaf, 0xbeef, 0x5411] >>> (\ (X a) -> showString "0x" . showHex a $ "") $ foldMap' X bits "0x42"
С версии: base-4.13.0.0
foldr :: (a -> b -> b) -> b -> t a -> b Источник
Правоассоциативный fold структуры, ленивый в накопителе.
В случае списков, foldr, когда применяется к бинарному оператору, начальному значению (обычно правому тождеству оператора) и списку, уменьшает список с использованием бинарного оператора справа налево:
foldr f z [x1, x2, ..., xn] == x1 `f` (x2 `f` ... (xn `f` z)...)
Обратите внимание, что поскольку головка результирующего выражения генерируется применением оператора к первому элементу списка, при использовании оператора, ленивого в правом аргументе, foldr может генерировать завершающее выражение из неограниченного списка.
Для общей структуры Foldable это должно быть семантически идентично,
foldr f z = foldr f z . toList
Примеры
Базовое использование:
>>> foldr (||) False [False, True, False] True
>>> foldr (||) False [] False
>>> foldr (\c acc -> acc ++ [c]) "foo" ['a', 'b', 'c', 'd'] "foodcba"
Бесконечные структуры
⚠️ Применение foldr к бесконечным структурам обычно не завершается.
Он может все же завершиться в одном из следующих случаев:
- функция складывания является короткой
- функция складывания ленивая в своем втором аргументе
Короткое замыкание
(||) короткое замыкание на значениях True, поэтому следующее завершается, так как есть значение True в конечном расстоянии от левой стороны:
>>> foldr (||) False (True : repeat False) True
Но следующее не завершается:
>>> foldr (||) False (repeat False ++ [True]) * Hangs forever *
Ленивость во втором аргументе
Применение foldr к бесконечным структурам завершается, когда оператор ленив в своем втором аргументе (в этом случае начальный накопитель никогда не используется и может быть оставлен undefined, но [] более понятен):
>>> take 5 $ foldr (\i acc -> i : fmap (+3) acc) [] (repeat 1) [1,4,7,10,13]
foldr' :: (a -> b -> b) -> b -> t a -> b Источник
foldr' - это вариант foldr, который выполняет строгое сокращение справа налево, т. е. начиная с правого элемента. Структура входных данных *должна* быть конечной, в противном случае foldr' исчерпывает ресурсы (дивергирует).
Если вы хотите строгий правый fold в постоянном объеме памяти, вам нужна структура, которая поддерживает более быстрый доступ к правому элементу, чем O(n), например Seq из пакета containers.
Этот метод не работает в постоянном объеме памяти для структур, таких как списки, которые не поддерживают эффективную итерацию справа налево и поэтому требуют O(n) объема памяти для выполнения сокращения справа налево. Использование этого метода со структурой такого типа является признаком того, что выбранная структура может быть неподходящей для поставленной задачи. Если порядок объединения элементов не важен, используйте foldl' вместо этого.
С версии: base-4.6.0.0
foldl :: (b -> a -> b) -> b -> t a -> b Источник
Левоассоциативный fold структуры, ленивый в накопителе. Это редко то, что вам нужно, но может хорошо работать со структурами с эффективной последовательностью справа налево и оператором, ленивым в левом аргументе.
В случае списков, foldl, когда применяется к бинарному оператору, начальному значению (обычно левому тождеству оператора) и списку, уменьшает список с использованием бинарного оператора слева направо:
foldl f z [x1, x2, ..., xn] == (...((z `f` x1) `f` x2) `f`...) `f` xn
Обратите внимание, что для получения внешнего применения оператора необходимо пройти весь входной список. Как и все левоассоциативные folds, foldl расходится, если получает бесконечный список.
Если вам нужен эффективный строгий левоассоциативный fold, вы, вероятно, должны использовать foldl' вместо foldl. Причина в том, что последний не принуждает к вычислению *внутренних* результатов (например, z `f` x1 в приведенном выше примере) перед их применением к оператору (например, к (`f` x2)). Это приводит к цепочке thunk длиной O(n) элементов, которые затем должны быть вычислены снаружи внутрь.
Для общей структуры Foldable это должно быть семантически идентично:
foldl f z = foldl f z . toList
Примеры
Первый пример - это строгий fold, который на практике лучше всего выполнять с помощью foldl'.
>>> foldl (+) 42 [1,2,3,4] 52
Хотя результат ниже ленив, входной данные переворачиваются перед добавлением в начальный накопитель, поэтому рекурсия начинается только после прохождения всего входного строкового значения.
>>> foldl (\acc c -> c : acc) "abcd" "efgh" "hgfeabcd"
Левый fold структуры, которая бесконечна справа, не может завершиться, даже когда для любого конечного ввода fold просто возвращает начальный накопитель:
>>> foldl (\a _ -> a) 0 $ repeat 1 * Hangs forever *
ВНИМАНИЕ: когда дело доходит до списков, вы всегда хотите использовать либо foldl' , либо foldr вместо этого.
foldl' :: (b -> a -> b) -> b -> t a -> b Источник
Левоассоциативный fold структуры, но со строгим применением оператора.
Это гарантирует, что каждый шаг fold будет принужден к слабой нормальной форме перед применением, избегая сбора thunk, которые в противном случае произошли бы. Это часто то, что вам нужно для строгого сокращения конечной структуры до одного строгого результата (например, sum).
Для общей структуры Foldable это должно быть семантически идентично,
foldl' f z = foldl' f z . toList
С версии: base-4.6.0.0
foldr1 :: (a -> a -> a) -> t a -> a Источник
Вариант foldr, у которого нет базового случая, и поэтому он может применяться только к непустым структурам.
Эта функция неполна и вызовет исключение во время выполнения, если структура окажется пустой.
Примеры
Базовое использование:
>>> foldr1 (+) [1..4] 10
>>> foldr1 (+) [] Exception: Prelude.foldr1: empty list
>>> foldr1 (+) Nothing *** Exception: foldr1: empty structure
>>> foldr1 (-) [1..4] -2
>>> foldr1 (&&) [True, False, True, True] False
>>> foldr1 (||) [False, False, True, True] True
>>> foldr1 (+) [1..] * Hangs forever *
foldl1 :: (a -> a -> a) -> t a -> a Источник
Вариант foldl , у которого нет базового случая, и поэтому он может применяться только к непустым структурам.
Эта функция неполна и вызовет исключение во время выполнения, если структура окажется пустой.
foldl1 f = foldl1 f . toList
Примеры
Базовое использование:
>>> foldl1 (+) [1..4] 10
>>> foldl1 (+) [] *** Exception: Prelude.foldl1: empty list
>>> foldl1 (+) Nothing *** Exception: foldl1: empty structure
>>> foldl1 (-) [1..4] -8
>>> foldl1 (&&) [True, False, True, True] False
>>> foldl1 (||) [False, False, True, True] True
>>> foldl1 (+) [1..] * Hangs forever *
Список элементов структуры, слева направо. Если весь список предназначен для сокращения с помощью fold, просто выполните fold структуры напрямую, пропустив список.
Примеры
Базовое использование:
>>> toList Nothing []
>>> toList (Just 42) [42]
>>> toList (Left "foo") []
>>> toList (Node (Leaf 5) 17 (Node Empty 12 (Leaf 8))) [5,17,12,8]
Для списков, toList является тождественной операцией:
>>> toList [1, 2, 3] [1,2,3]
С версии: base-4.8.0.0
Проверка, пуста ли структура. По умолчанию реализация является левоассоциативной и ленивой как для начального элемента, так и для аккумулятора. Таким образом, оптимизирована для структур, где к первому элементу можно получить доступ за постоянное время. Структуры, для которых это не так, должны иметь реализацию отличную от по умолчанию.
Примеры
Базовое использование:
>>> null [] True
>>> null [1] False
null ожидается, что завершится даже для бесконечных структур. Реализация по умолчанию завершается при условии, что структура ограничена слева (существует крайний левый элемент).
>>> null [1..] False
С версии: base-4.8.0.0
Возвращает размер/длину конечной структуры как Int. Реализация по умолчанию просто считает элементы, начиная с крайнего левого. Экземпляры для структур, которые могут вычислить количество элементов быстрее, чем подсчетом по элементам, должны предоставить специализированную реализацию.
Примеры
Базовое использование:
>>> length [] 0
>>> length ['a', 'b', 'c'] 3 >>> length [1..] * Hangs forever *
С версии: base-4.8.0.0
elem :: Eq a => a -> t a -> Bool infix 4 Источник
Является ли элемент частью структуры?
Примечание: elem часто используется в виде инфиксной операции.
Примеры
Базовое использование:
>>> 3 `elem` [] False
>>> 3 `elem` [1,2] False
>>> 3 `elem` [1,2,3,4,5] True
Для бесконечных структур, по умолчанию elem завершается, если искомое значение находится на конечном расстоянии слева от структуры:
>>> 3 `elem` [1..] True
>>> 3 `elem` ([4..] ++ [3]) * Hangs forever *
С версии: base-4.8.0.0
maximum :: Ord a => t a -> a Источник
Наибольший элемент в непустой структуре. Эта функция эквивалентна foldr1 max, а её поведение для структур с несколькими наибольшими элементами зависит от соответствующей реализации max. Для реализации max по умолчанию (max x y = if x <= y
then y else x) порядок структуры используется в качестве разрыва: если есть несколько наибольших элементов, выбирается самый правый из них (это эквивалентно maximumBy compare).
Функция является частичной и вызовет исключение во время выполнения, если структура пуста. Структура, поддерживающая произвольный доступ и сохраняющая элементы в порядке, должна предоставить специализированную реализацию, чтобы вернуть максимальное значение за время меньше, чем линейное.
Примеры
Базовое использование:
>>> maximum [1..10] 10
>>> maximum [] *** Exception: Prelude.maximum: empty list
>>> maximum Nothing *** Exception: maximum: empty structure
ПРЕДУПРЕЖДЕНИЕ: Эта функция частична для потенциально пустых структур, таких как списки.
С версии: base-4.8.0.0
minimum :: Ord a => t a -> a Источник
Наименьший элемент непустой структуры. Эта функция эквивалентна foldr1 min, а её поведение для структур с несколькими наименьшими элементами зависит от соответствующей реализации min. Для реализации min по умолчанию (min x y = if x <= y
then x else y) порядок структуры используется в качестве разрыва: если есть несколько наименьших элементов, выбирается самый левый из них (это эквивалентно minimumBy compare).
Функция является частичной и вызовет исключение во время выполнения, если структура пуста. Структура, поддерживающая произвольный доступ и сохраняющая элементы в порядке, должна предоставить специализированную реализацию, чтобы вернуть минимальное значение за время меньше, чем линейное.
Примеры
Базовое использование:
>>> minimum [1..10] 1
>>> minimum [] *** Exception: Prelude.minimum: empty list
>>> minimum Nothing *** Exception: minimum: empty structure
ПРЕДУПРЕЖДЕНИЕ: Эта функция частична для потенциально пустых структур, таких как списки.
С версии: base-4.8.0.0
sum :: Num a => t a -> a Источник
Функция sum вычисляет сумму чисел структуры.
Примеры
Базовое использование:
>>> sum [] 0
>>> sum [42] 42
>>> sum [1..10] 55
>>> sum [4.1, 2.0, 1.7] 7.8
>>> sum [1..] * Hangs forever *
С версии: base-4.8.0.0
product :: Num a => t a -> a Источник
Функция product вычисляет произведение чисел структуры.
Примеры
Базовое использование:
>>> product [] 1
>>> product [42] 42
>>> product [1..10] 3628800
>>> product [4.1, 2.0, 1.7] 13.939999999999998
>>> product [1..] * Hangs forever *
С версии: base-4.8.0.0
Примеры
Определено в Data.Semigroup Методыfold :: Monoid m => First m -> m Исходный код foldMap :: Monoid m => (a -> m) -> First a -> m Исходный код foldMap' :: Monoid m => (a -> m) -> First a -> m Исходный код foldr :: (a -> b -> b) -> b -> First a -> b Исходный код foldr' :: (a -> b -> b) -> b -> First a -> b Исходный код foldl :: (b -> a -> b) -> b -> First a -> b Исходный код foldl' :: (b -> a -> b) -> b -> First a -> b Исходный код foldr1 :: (a -> a -> a) -> First a -> a Исходный код foldl1 :: (a -> a -> a) -> First a -> a Исходный код toList :: First a -> [a] Исходный код null :: First a -> Boolean Исходный код length :: First a -> Целое число Исходный код elem :: Eq a => a -> First a -> Boolean Исходный код maximum :: Ord a => First a -> a Исходный код minimum :: Ord a => First a -> a Исходный код sum :: Num a => First a -> a Исходный код product :: Num a => First a -> a Исходный код | |
| Foldable Last Исходный код | С момента: base-4.9.0.0 |
Определено в Data.Semigroup Методыfold :: Monoid m => Last m -> m Исходный код foldMap :: Monoid m => (a -> m) -> Last a -> m Исходный код foldMap' :: Monoid m => (a -> m) -> Last a -> m Исходный код foldr :: (a -> b -> b) -> b -> Last a -> b Исходный код foldr' :: (a -> b -> b) -> b -> Last a -> b Исходный код foldl :: (b -> a -> b) -> b -> Last a -> b Исходный код foldl' :: (b -> a -> b) -> b -> Last a -> b Исходный код foldr1 :: (a -> a -> a) -> Last a -> a Исходный код foldl1 :: (a -> a -> a) -> Last a -> a Исходный код toList :: Last a -> [a] Исходный код null :: Last a -> Bool Исходный код length :: Last a -> Int Исходный код elem :: Eq a => a -> Last a -> Bool Исходный код maximum :: Ord a => Last a -> a Исходный код minimum :: Ord a => Last a -> a Исходный код sum :: Num a => Last a -> a Исходный код product :: Num a => Last a -> a Исходный код | |
| Foldable Max Исходный код | С момента: base-4.9.0.0 |
Определено в Data.Semigroup Методыfold :: Monoid m => Max m -> m Исходный код foldMap :: Monoid m => (a -> m) -> Max a -> m Исходный код foldMap' :: Monoid m => (a -> m) -> Max a -> m Исходный код foldr :: (a -> b -> b) -> b -> Max a -> b Исходный код foldr' :: (a -> b -> b) -> b -> Max a -> b Исходный код foldl :: (b -> a -> b) -> b -> Max a -> b Исходный код foldl' :: (b -> a -> b) -> b -> Max a -> b Исходный код foldr1 :: (a -> a -> a) -> Max a -> a Исходный код foldl1 :: (a -> a -> a) -> Max a -> a Исходный код toList :: Max a -> [a] Исходный код null :: Max a -> Bool Исходный код length :: Max a -> Int Исходный код elem :: Eq a => a -> Max a -> Bool Исходный код maximum :: Ord a => Max a -> a Исходный код minimum :: Ord a => Max a -> a Исходный код sum :: Num a => Max a -> a Исходный код product :: Num a => Max a -> a Исходный код | |
| Foldable Min Исходный код | С версии: base-4.9.0.0 |
Определено в Data.Semigroup Методыfold :: Monoid m => Min m -> m Исходный код foldMap :: Monoid m => (a -> m) -> Min a -> m Исходный код foldMap' :: Monoid m => (a -> m) -> Min a -> m Исходный код foldr :: (a -> b -> b) -> b -> Min a -> b Исходный код foldr' :: (a -> b -> b) -> b -> Min a -> b Исходный код foldl :: (b -> a -> b) -> b -> Min a -> b Исходный код foldl' :: (b -> a -> b) -> b -> Min a -> b Исходный код foldr1 :: (a -> a -> a) -> Min a -> a Исходный код foldl1 :: (a -> a -> a) -> Min a -> a Исходный код toList :: Min a -> [a] Исходный код null :: Min a -> Bool Исходный код length :: Min a -> Int Исходный код elem :: Eq a => a -> Min a -> Bool Исходный код maximum :: Ord a => Min a -> a Исходный код minimum :: Ord a => Min a -> a Исходный код sum :: Num a => Min a -> a Исходный код product :: Num a => Min a -> a Исходный код | |
| Foldable NonEmpty Исходный код | С момента: base-4.9.0.0 |
Определено в GHC.Internal.Data.Foldable Методыfold :: Monoid m => First m -> m Источник foldMap :: Monoid m => (a -> m) -> First a -> m Источник foldMap' :: Monoid m => (a -> m) -> First a -> m Источник foldr :: (a -> b -> b) -> b -> First a -> b Источник foldr' :: (a -> b -> b) -> b -> First a -> b Источник foldl :: (b -> a -> b) -> b -> First a -> b Источник foldl' :: (b -> a -> b) -> b -> First a -> b Источник foldr1 :: (a -> a -> a) -> First a -> a Источник foldl1 :: (a -> a -> a) -> First a -> a Источник toList :: First a -> [a] Источник null :: First a -> Bool Источник length :: First a -> Int Источник elem :: Eq a => a -> First a -> Bool Источник maximum :: Ord a => First a -> a Источник minimum :: Ord a => First a -> a Источник | |
| Foldable Last Источник | С момента: base-4.8.0.0 |
Определено в GHC.Internal.Data.Foldable Методыfold :: Моноид m => Last m -> m Исходный код foldMap :: Моноид m => (a -> m) -> Last a -> m Исходный код foldMap' :: Моноид m => (a -> m) -> Last a -> m Исходный код foldr :: (a -> b -> b) -> b -> Last a -> b Исходный код foldr' :: (a -> b -> b) -> b -> Last a -> b Исходный код foldl :: (b -> a -> b) -> b -> Last a -> b Исходный код foldl' :: (b -> a -> b) -> b -> Last a -> b Исходный код foldr1 :: (a -> a -> a) -> Last a -> a Исходный код foldl1 :: (a -> a -> a) -> Last a -> a Исходный код toList :: Last a -> [a] Исходный код null :: Last a -> Булево Исходный код length :: Last a -> Целое Исходный код elem :: Eq a => a -> Last a -> Булево Исходный код maximum :: Ord a => Last a -> a Исходный код minimum :: Ord a => Last a -> a Исходный код sum :: Num a => Last a -> a Исходный код product :: Num a => Last a -> a Исходный код | |
| Foldable Down Исходный код | С момента: base-4.12.0.0 |
Определено в GHC.Internal.Data.Foldable Методыfold :: Моноид m => Down m -> m Исходный код foldMap :: Моноид m => (a -> m) -> Down a -> m Исходный код foldMap' :: Моноид m => (a -> m) -> Down a -> m Исходный код foldr :: (a -> b -> b) -> b -> Down a -> b Исходный код foldr' :: (a -> b -> b) -> b -> Down a -> b Исходный код foldl :: (b -> a -> b) -> b -> Down a -> b Исходный код foldl' :: (b -> a -> b) -> b -> Down a -> b Исходный код foldr1 :: (a -> a -> a) -> Down a -> a Исходный код foldl1 :: (a -> a -> a) -> Down a -> a Исходный код toList :: Down a -> [a] Исходный код null :: Down a -> Boolean Исходный код length :: Down a -> Целое число Исходный код elem :: Eq a => a -> Down a -> Boolean Исходный код maximum :: Ord a => Down a -> a Исходный код minimum :: Ord a => Down a -> a Исходный код sum :: Num a => Down a -> a Исходный код product :: Num a => Down a -> a Исходный код | |
| Foldable Dual Исходный код | С: base-4.8.0.0 |
Определено в GHC.Internal.Data.Foldable Методыfold :: Monoid m => Dual m -> m Исходный код foldMap :: Monoid m => (a -> m) -> Dual a -> m Исходный код foldMap' :: Monoid m => (a -> m) -> Dual a -> m Исходный код foldr :: (a -> b -> b) -> b -> Dual a -> b Исходный код foldr' :: (a -> b -> b) -> b -> Dual a -> b Исходный код foldl :: (b -> a -> b) -> b -> Dual a -> b Исходный код foldl' :: (b -> a -> b) -> b -> Dual a -> b Исходный код foldr1 :: (a -> a -> a) -> Dual a -> a Исходный код foldl1 :: (a -> a -> a) -> Dual a -> a Исходный код toList :: Dual a -> [a] Исходный код null :: Dual a -> Bool Исходный код length :: Dual a -> Int Исходный код elem :: Eq a => a -> Dual a -> Bool Исходный код maximum :: Ord a => Dual a -> a Исходный код minimum :: Ord a => Dual a -> a Исходный код sum :: Num a => Dual a -> a Исходный код product :: Num a => Dual a -> a Исходный код | |
| Foldable Product Исходный код | С: base-4.8.0.0 |
Определено в GHC.Internal.Data.Foldable Методыfold :: Monoid m => Sum m -> m Исходный код foldMap :: Monoid m => (a -> m) -> Sum a -> m Исходный код foldMap' :: Monoid m => (a -> m) -> Sum a -> m Исходный код foldr :: (a -> b -> b) -> b -> Sum a -> b Исходный код foldr' :: (a -> b -> b) -> b -> Sum a -> b Исходный код foldl :: (b -> a -> b) -> b -> Sum a -> b Исходный код foldl' :: (b -> a -> b) -> b -> Sum a -> b Исходный код foldr1 :: (a -> a -> a) -> Sum a -> a Исходный код foldl1 :: (a -> a -> a) -> Sum a -> a Исходный код toList :: Sum a -> [a] Исходный код null :: Sum a -> Boolean Исходный код length :: Sum a -> Целое Исходный код elem :: Eq a => a -> Sum a -> Boolean Исходный код maximum :: Ord a => Sum a -> a Исходный код minimum :: Ord a => Sum a -> a Исходный код sum :: Num a => Sum a -> a Исходный код product :: Num a => Sum a -> a Исходный код | |
| Foldable ZipList Исходный код | С момента: base-4.9.0.0 |
Определено в GHC.Internal.Functor.ZipList Методыfold :: Monoid m => ZipList m -> m Источник foldMap :: Monoid m => (a -> m) -> ZipList a -> m Источник foldMap' :: Monoid m => (a -> m) -> ZipList a -> m Источник foldr :: (a -> b -> b) -> b -> ZipList a -> b Источник foldr' :: (a -> b -> b) -> b -> ZipList a -> b Источник foldl :: (b -> a -> b) -> b -> ZipList a -> b Источник foldl' :: (b -> a -> b) -> b -> ZipList a -> b Источник foldr1 :: (a -> a -> a) -> ZipList a -> a Источник foldl1 :: (a -> a -> a) -> ZipList a -> a Источник toList :: ZipList a -> [a] Источник null :: ZipList a -> Bool Источник length :: ZipList a -> Int Источник elem :: Eq a => a -> ZipList a -> Bool Источник maximum :: Ord a => ZipList a -> a Источник minimum :: Ord a => ZipList a -> a Источник | |
| Foldable Par1 Источник | С момента: base-4.9.0.0 |
Определено в GHC.Internal.Data.Foldable Методыfold :: Monoid m => Par1 m -> m Исходный код foldMap :: Monoid m => (a -> m) -> Par1 a -> m Исходный код foldMap' :: Monoid m => (a -> m) -> Par1 a -> m Исходный код foldr :: (a -> b -> b) -> b -> Par1 a -> b Исходный код foldr' :: (a -> b -> b) -> b -> Par1 a -> b Исходный код foldl :: (b -> a -> b) -> b -> Par1 a -> b Исходный код foldl' :: (b -> a -> b) -> b -> Par1 a -> b Исходный код foldr1 :: (a -> a -> a) -> Par1 a -> a Исходный код foldl1 :: (a -> a -> a) -> Par1 a -> a Исходный код toList :: Par1 a -> [a] Исходный код null :: Par1 a -> Bool Исходный код length :: Par1 a -> Int Исходный код elem :: Eq a => a -> Par1 a -> Bool Исходный код maximum :: Ord a => Par1 a -> a Исходный код minimum :: Ord a => Par1 a -> a Исходный код sum :: Num a => Par1 a -> a Исходный код product :: Num a => Par1 a -> a Исходный код | |
| Foldable TyVarBndr Исходный код | |
Определено в GHC.Internal.Data.Foldable Методыfold :: Monoid m => Maybe m -> m Исходный код foldMap :: Monoid m => (a -> m) -> Maybe a -> m Исходный код foldMap' :: Monoid m => (a -> m) -> Maybe a -> m Исходный код foldr :: (a -> b -> b) -> b -> Maybe a -> b Исходный код foldr' :: (a -> b -> b) -> b -> Maybe a -> b Исходный код foldl :: (b -> a -> b) -> b -> Maybe a -> b Исходный код foldl' :: (b -> a -> b) -> b -> Maybe a -> b Исходный код foldr1 :: (a -> a -> a) -> Maybe a -> a Исходный код foldl1 :: (a -> a -> a) -> Maybe a -> a Исходный код toList :: Maybe a -> [a] Исходный код null :: Maybe a -> Bool Исходный код length :: Maybe a -> Int Исходный код elem :: Eq a => a -> Maybe a -> Bool Исходный код maximum :: Ord a => Maybe a -> a Исходный код minimum :: Ord a => Maybe a -> a Исходный код sum :: Num a => Maybe a -> a Исходный код product :: Num a => Maybe a -> a Исходный код | |
| Foldable Solo Исходный код | С: base-4.15 |
Определено в GHC.Internal.Data.Foldable Краткое описание методовfold :: Monoid m => Solo m -> m Исходный код foldMap :: Monoid m => (a -> m) -> Solo a -> m Исходный код foldMap' :: Monoid m => (a -> m) -> Solo a -> m Исходный код foldr :: (a -> b -> b) -> b -> Solo a -> b Исходный код foldr' :: (a -> b -> b) -> b -> Solo a -> b Исходный код foldl :: (b -> a -> b) -> b -> Solo a -> b Исходный код foldl' :: (b -> a -> b) -> b -> Solo a -> b Исходный код foldr1 :: (a -> a -> a) -> Solo a -> a Исходный код foldl1 :: (a -> a -> a) -> Solo a -> a Исходный код toList :: Solo a -> [a] Исходный код null :: Solo a -> Bool Исходный код length :: Solo a -> Int Исходный код elem :: Eq a => a -> Solo a -> Bool Исходный код maximum :: Ord a => Solo a -> a Исходный код minimum :: Ord a => Solo a -> a Исходный код sum :: Num a => Solo a -> a Исходный код product :: Num a => Solo a -> a Исходный код | |
| Foldable [] Исходный код | С версии: base-2.1 |
Определено в GHC.Internal.Data.Foldable Краткое описание методовfold :: Monoid m => [m] -> m Исходный код foldMap :: Monoid m => (a -> m) -> [a] -> m Исходный код foldMap' :: Monoid m => (a -> m) -> [a] -> m Исходный код foldr :: (a -> b -> b) -> b -> [a] -> b Исходный код foldr' :: (a -> b -> b) -> b -> [a] -> b Исходный код foldl :: (b -> a -> b) -> b -> [a] -> b Исходный код foldl' :: (b -> a -> b) -> b -> [a] -> b Исходный код foldr1 :: (a -> a -> a) -> [a] -> a Исходный код foldl1 :: (a -> a -> a) -> [a] -> a Исходный код toList :: [a] -> [a] Исходный код null :: [a] -> Bool Исходный код length :: [a] -> Int Исходный код elem :: Eq a => a -> [a] -> Bool Исходный код maximum :: Ord a => [a] -> a Исходный код minimum :: Ord a => [a] -> a Исходный код sum :: Num a => [a] -> a Исходный код product :: Num a => [a] -> a Исходный код | |
| Foldable (Arg a) Source | Since: base-4.9.0.0 |
Определено в Data.Semigroup Методыfold :: Monoid m => Arg a m -> m Source foldMap :: Monoid m => (a0 -> m) -> Arg a a0 -> m Source foldMap' :: Monoid m => (a0 -> m) -> Arg a a0 -> m Source foldr :: (a0 -> b -> b) -> b -> Arg a a0 -> b Source foldr' :: (a0 -> b -> b) -> b -> Arg a a0 -> b Source foldl :: (b -> a0 -> b) -> b -> Arg a a0 -> b Source foldl' :: (b -> a0 -> b) -> b -> Arg a a0 -> b Source foldr1 :: (a0 -> a0 -> a0) -> Arg a a0 -> a0 Source foldl1 :: (a0 -> a0 -> a0) -> Arg a a0 -> a0 Source toList :: Arg a a0 -> [a0] Source null :: Arg a a0 -> Bool Source length :: Arg a a0 -> Int Source elem :: Eq a0 => a0 -> Arg a a0 -> Bool Source maximum :: Ord a0 => Arg a a0 -> a0 Source minimum :: Ord a0 => Arg a a0 -> a0 Source | |
| Foldable (Array i) Source | Since: base-4.8.0.0 |
Определено в GHC.Internal.Data.Foldable Методыfold :: Monoid m => Either a m -> m Исходный код foldMap :: Monoid m => (a0 -> m) -> Either a a0 -> m Исходный код foldMap' :: Monoid m => (a0 -> m) -> Either a a0 -> m Исходный код foldr :: (a0 -> b -> b) -> b -> Either a a0 -> b Исходный код foldr' :: (a0 -> b -> b) -> b -> Either a a0 -> b Исходный код foldl :: (b -> a0 -> b) -> b -> Either a a0 -> b Исходный код foldl' :: (b -> a0 -> b) -> b -> Either a a0 -> b Исходный код foldr1 :: (a0 -> a0 -> a0) -> Either a a0 -> a0 Исходный код foldl1 :: (a0 -> a0 -> a0) -> Either a a0 -> a0 Исходный код toList :: Either a a0 -> [a0] Исходный код null :: Either a a0 -> Boolean Исходный код length :: Either a a0 -> Целое Исходный код elem :: Eq a0 => a0 -> Either a a0 -> Boolean Исходный код maximum :: Ord a0 => Either a a0 -> a0 Исходный код minimum :: Ord a0 => Either a a0 -> a0 Исходный код sum :: Num a0 => Either a a0 -> a0 Исходный код product :: Num a0 => Either a a0 -> a0 Исходный код | |
| Foldable (Proxy :: Тип -> Тип) Исходный код | С момента: base-4.7.0.0 |
Определено в GHC.Internal.Data.Foldable Методыfold :: Monoid m => Proxy m -> m Исходный код foldMap :: Monoid m => (a -> m) -> Proxy a -> m Исходный код foldMap' :: Monoid m => (a -> m) -> Proxy a -> m Исходный код foldr :: (a -> b -> b) -> b -> Proxy a -> b Исходный код foldr' :: (a -> b -> b) -> b -> Proxy a -> b Исходный код foldl :: (b -> a -> b) -> b -> Proxy a -> b Исходный код foldl' :: (b -> a -> b) -> b -> Proxy a -> b Исходный код foldr1 :: (a -> a -> a) -> Proxy a -> a Исходный код foldl1 :: (a -> a -> a) -> Proxy a -> a Исходный код toList :: Proxy a -> [a] Исходный код null :: Proxy a -> Булево Исходный код length :: Proxy a -> Целое Исходный код elem :: Eq a => a -> Proxy a -> Булево Исходный код maximum :: Ord a => Proxy a -> a Исходный код minimum :: Ord a => Proxy a -> a Исходный код sum :: Num a => Proxy a -> a Исходный код product :: Num a => Proxy a -> a Исходный код | |
| Foldable (U1 :: Тип -> Тип) Исходный код | С момента: base-4.9.0.0 |
Определено в GHC.Internal.Data.Foldable Методыfold :: Monoid m => U1 m -> m Исходный код foldMap :: Monoid m => (a -> m) -> U1 a -> m Исходный код foldMap' :: Monoid m => (a -> m) -> U1 a -> m Исходный код foldr :: (a -> b -> b) -> b -> U1 a -> b Исходный код foldr' :: (a -> b -> b) -> b -> U1 a -> b Исходный код foldl :: (b -> a -> b) -> b -> U1 a -> b Исходный код foldl' :: (b -> a -> b) -> b -> U1 a -> b Исходный код foldr1 :: (a -> a -> a) -> U1 a -> a Исходный код foldl1 :: (a -> a -> a) -> U1 a -> a Исходный код toList :: U1 a -> [a] Исходный код null :: U1 a -> Bool Исходный код length :: U1 a -> Int Исходный код elem :: Eq a => a -> U1 a -> Bool Исходный код maximum :: Ord a => U1 a -> a Исходный код minimum :: Ord a => U1 a -> a Исходный код sum :: Num a => U1 a -> a Исходный код product :: Num a => U1 a -> a Исходный код | |
| Foldable (UAddr :: Тип -> Тип) Исходный код | С момента: base-4.9.0.0 |
Определено в GHC.Internal.Data.Foldable Методыfold :: Monoid m => UAddr m -> m Исходный код foldMap :: Monoid m => (a -> m) -> UAddr a -> m Исходный код foldMap' :: Monoid m => (a -> m) -> UAddr a -> m Исходный код foldr :: (a -> b -> b) -> b -> UAddr a -> b Исходный код foldr' :: (a -> b -> b) -> b -> UAddr a -> b Исходный код foldl :: (b -> a -> b) -> b -> UAddr a -> b Исходный код foldl' :: (b -> a -> b) -> b -> UAddr a -> b Исходный код foldr1 :: (a -> a -> a) -> UAddr a -> a Исходный код foldl1 :: (a -> a -> a) -> UAddr a -> a Исходный код toList :: UAddr a -> [a] Исходный код null :: UAddr a -> Bool Исходный код length :: UAddr a -> Int Исходный код elem :: Eq a => a -> UAddr a -> Bool Исходный код maximum :: Ord a => UAddr a -> a Исходный код minimum :: Ord a => UAddr a -> a Исходный код sum :: Num a => UAddr a -> a Исходный код product :: Num a => UAddr a -> a Исходный код | |
| Foldable (UChar :: Тип -> Тип) Исходный код | С момента: base-4.9.0.0 |
Определено в GHC.Internal.Data.Foldable Методыfold :: Monoid m => UChar m -> m Исходный код foldMap :: Monoid m => (a -> m) -> UChar a -> m Исходный код foldMap' :: Monoid m => (a -> m) -> UChar a -> m Исходный код foldr :: (a -> b -> b) -> b -> UChar a -> b Исходный код foldr' :: (a -> b -> b) -> b -> UChar a -> b Исходный код foldl :: (b -> a -> b) -> b -> UChar a -> b Исходный код foldl' :: (b -> a -> b) -> b -> UChar a -> b Исходный код foldr1 :: (a -> a -> a) -> UChar a -> a Исходный код foldl1 :: (a -> a -> a) -> UChar a -> a Исходный код toList :: UChar a -> [a] Исходный код null :: UChar a -> Bool Исходный код length :: UChar a -> Int Исходный код elem :: Eq a => a -> UChar a -> Bool Исходный код maximum :: Ord a => UChar a -> a Исходный код minimum :: Ord a => UChar a -> a Исходный код sum :: Num a => UChar a -> a Исходный код product :: Num a => UChar a -> a Исходный код | |
| Foldable (UDouble :: Тип -> Тип) Исходный код | С момента: base-4.9.0.0 |
Определено в GHC.Internal.Data.Foldable Методыfold :: Monoid m => UFloat m -> m Исходный код foldMap :: Monoid m => (a -> m) -> UFloat a -> m Исходный код foldMap' :: Monoid m => (a -> m) -> UFloat a -> m Исходный код foldr :: (a -> b -> b) -> b -> UFloat a -> b Исходный код foldr' :: (a -> b -> b) -> b -> UFloat a -> b Исходный код foldl :: (b -> a -> b) -> b -> UFloat a -> b Исходный код foldl' :: (b -> a -> b) -> b -> UFloat a -> b Исходный код foldr1 :: (a -> a -> a) -> UFloat a -> a Исходный код foldl1 :: (a -> a -> a) -> UFloat a -> a Исходный код toList :: UFloat a -> [a] Исходный код null :: UFloat a -> Bool Исходный код length :: UFloat a -> Int Исходный код elem :: Eq a => a -> UFloat a -> Bool Исходный код maximum :: Ord a => UFloat a -> a Исходный код minimum :: Ord a => UFloat a -> a Исходный код sum :: Num a => UFloat a -> a Исходный код product :: Num a => UFloat a -> a Исходный код | |
| Foldable (UInt :: Type -> Type) Исходный код | С момента: base-4.9.0.0 |
Определено в GHC.Internal.Data.Foldable Методыfold :: Monoid m => UInt m -> m Исходный код foldMap :: Monoid m => (a -> m) -> UInt a -> m Исходный код foldMap' :: Monoid m => (a -> m) -> UInt a -> m Исходный код foldr :: (a -> b -> b) -> b -> UInt a -> b Исходный код foldr' :: (a -> b -> b) -> b -> UInt a -> b Исходный код foldl :: (b -> a -> b) -> b -> UInt a -> b Исходный код foldl' :: (b -> a -> b) -> b -> UInt a -> b Исходный код foldr1 :: (a -> a -> a) -> UInt a -> a Исходный код foldl1 :: (a -> a -> a) -> UInt a -> a Исходный код toList :: UInt a -> [a] Исходный код null :: UInt a -> Bool Исходный код length :: UInt a -> Int Исходный код elem :: Eq a => a -> UInt a -> Bool Исходный код maximum :: Ord a => UInt a -> a Исходный код minimum :: Ord a => UInt a -> a Исходный код sum :: Num a => UInt a -> a Исходный код product :: Num a => UInt a -> a Исходный код | |
| Foldable (UWord :: Type -> Type) Исходный код | С момента: base-4.9.0.0 |
Определено в GHC.Internal.Data.Foldable Методыfold :: Monoid m => UWord m -> m Источник foldMap :: Monoid m => (a -> m) -> UWord a -> m Источник foldMap' :: Monoid m => (a -> m) -> UWord a -> m Источник foldr :: (a -> b -> b) -> b -> UWord a -> b Источник foldr' :: (a -> b -> b) -> b -> UWord a -> b Источник foldl :: (b -> a -> b) -> b -> UWord a -> b Источник foldl' :: (b -> a -> b) -> b -> UWord a -> b Источник foldr1 :: (a -> a -> a) -> UWord a -> a Источник foldl1 :: (a -> a -> a) -> UWord a -> a Источник toList :: UWord a -> [a] Источник null :: UWord a -> Bool Источник length :: UWord a -> Int Источник elem :: Eq a => a -> UWord a -> Bool Источник maximum :: Ord a => UWord a -> a Источник minimum :: Ord a => UWord a -> a Источник | |
| Foldable (V1 :: Тип -> Тип) Источник | С тех пор как: base-4.9.0.0 |
Определено в GHC.Internal.Data.Foldable Методыfold :: Monoid m => V1 m -> m Источник foldMap :: Monoid m => (a -> m) -> V1 a -> m Источник foldMap' :: Monoid m => (a -> m) -> V1 a -> m Источник foldr :: (a -> b -> b) -> b -> V1 a -> b Источник foldr' :: (a -> b -> b) -> b -> V1 a -> b Источник foldl :: (b -> a -> b) -> b -> V1 a -> b Источник foldl' :: (b -> a -> b) -> b -> V1 a -> b Источник foldr1 :: (a -> a -> a) -> V1 a -> a Источник foldl1 :: (a -> a -> a) -> V1 a -> a Источник toList :: V1 a -> [a] Источник length :: V1 a -> Int Источник elem :: Eq a => a -> V1 a -> Bool Источник maximum :: Ord a => V1 a -> a Источник minimum :: Ord a => V1 a -> a Источник | |
| Foldable ((,) a) Источник | С момента: base-4.7.0.0 |
Определено в GHC.Internal.Data.Foldable Методыfold :: Monoid m => (a, m) -> m Источник foldMap :: Monoid m => (a0 -> m) -> (a, a0) -> m Источник foldMap' :: Monoid m => (a0 -> m) -> (a, a0) -> m Источник foldr :: (a0 -> b -> b) -> b -> (a, a0) -> b Источник foldr' :: (a0 -> b -> b) -> b -> (a, a0) -> b Источник foldl :: (b -> a0 -> b) -> b -> (a, a0) -> b Источник foldl' :: (b -> a0 -> b) -> b -> (a, a0) -> b Источник foldr1 :: (a0 -> a0 -> a0) -> (a, a0) -> a0 Источник foldl1 :: (a0 -> a0 -> a0) -> (a, a0) -> a0 Источник toList :: (a, a0) -> [a0] Источник null :: (a, a0) -> Bool Источник length :: (a, a0) -> Int Источник elem :: Eq a0 => a0 -> (a, a0) -> Bool Источник maximum :: Ord a0 => (a, a0) -> a0 Источник minimum :: Ord a0 => (a, a0) -> a0 Источник | |
| Foldable (Const m :: Type -> Type) Source | Since: base-4.7.0.0 |
Определено в GHC.Internal.Data.Functor.Const Методыfold :: Monoid m0 => Const m m0 -> m0 Source foldMap :: Monoid m0 => (a -> m0) -> Const m a -> m0 Source foldMap' :: Monoid m0 => (a -> m0) -> Const m a -> m0 Source foldr :: (a -> b -> b) -> b -> Const m a -> b Source foldr' :: (a -> b -> b) -> b -> Const m a -> b Source foldl :: (b -> a -> b) -> b -> Const m a -> b Source foldl' :: (b -> a -> b) -> b -> Const m a -> b Source foldr1 :: (a -> a -> a) -> Const m a -> a Source foldl1 :: (a -> a -> a) -> Const m a -> a Source toList :: Const m a -> [a] Source null :: Const m a -> Bool Source length :: Const m a -> Int Source elem :: Eq a => a -> Const m a -> Bool Source maximum :: Ord a => Const m a -> a Source minimum :: Ord a => Const m a -> a Source | |
| Foldable f => Foldable (Ap f) Source | Since: base-4.12.0.0 |
Определено в GHC.Internal.Data.Foldable Методыfold :: Monoid m => Ap f m -> m Исходный код foldMap :: Monoid m => (a -> m) -> Ap f a -> m Исходный код foldMap' :: Monoid m => (a -> m) -> Ap f a -> m Исходный код foldr :: (a -> b -> b) -> b -> Ap f a -> b Исходный код foldr' :: (a -> b -> b) -> b -> Ap f a -> b Исходный код foldl :: (b -> a -> b) -> b -> Ap f a -> b Исходный код foldl' :: (b -> a -> b) -> b -> Ap f a -> b Исходный код foldr1 :: (a -> a -> a) -> Ap f a -> a Исходный код foldl1 :: (a -> a -> a) -> Ap f a -> a Исходный код toList :: Ap f a -> [a] Исходный код null :: Ap f a -> Bool Исходный код length :: Ap f a -> Int Исходный код elem :: Eq a => a -> Ap f a -> Bool Исходный код maximum :: Ord a => Ap f a -> a Исходный код minimum :: Ord a => Ap f a -> a Исходный код sum :: Num a => Ap f a -> a Исходный код product :: Num a => Ap f a -> a Исходный код | |
| Foldable f => Foldable (Alt f) Исходный код | С момента: base-4.12.0.0 |
Определено в GHC.Internal.Data.Foldable Методыfold :: Monoid m => Alt f m -> m Источник foldMap :: Monoid m => (a -> m) -> Alt f a -> m Источник foldMap' :: Monoid m => (a -> m) -> Alt f a -> m Источник foldr :: (a -> b -> b) -> b -> Alt f a -> b Источник foldr' :: (a -> b -> b) -> b -> Alt f a -> b Источник foldl :: (b -> a -> b) -> b -> Alt f a -> b Источник foldl' :: (b -> a -> b) -> b -> Alt f a -> b Источник foldr1 :: (a -> a -> a) -> Alt f a -> a Источник foldl1 :: (a -> a -> a) -> Alt f a -> a Источник toList :: Alt f a -> [a] Источник null :: Alt f a -> Булево Источник length :: Alt f a -> Целое Источник elem :: Eq a => a -> Alt f a -> Булево Источник maximum :: Ord a => Alt f a -> a Источник minimum :: Ord a => Alt f a -> a Источник | |
| Foldable f => Foldable (Rec1 f) Источник | С тех пор: base-4.9.0.0 |
Определено в GHC.Internal.Data.Foldable Методыfold :: Monoid m => Rec1 f m -> m Исходный код foldMap :: Monoid m => (a -> m) -> Rec1 f a -> m Исходный код foldMap' :: Monoid m => (a -> m) -> Rec1 f a -> m Исходный код foldr :: (a -> b -> b) -> b -> Rec1 f a -> b Исходный код foldr' :: (a -> b -> b) -> b -> Rec1 f a -> b Исходный код foldl :: (b -> a -> b) -> b -> Rec1 f a -> b Исходный код foldl' :: (b -> a -> b) -> b -> Rec1 f a -> b Исходный код foldr1 :: (a -> a -> a) -> Rec1 f a -> a Исходный код foldl1 :: (a -> a -> a) -> Rec1 f a -> a Исходный код toList :: Rec1 f a -> [a] Исходный код null :: Rec1 f a -> Bool Исходный код length :: Rec1 f a -> Int Исходный код elem :: Eq a => a -> Rec1 f a -> Bool Исходный код maximum :: Ord a => Rec1 f a -> a Исходный код minimum :: Ord a => Rec1 f a -> a Исходный код sum :: Num a => Rec1 f a -> a Исходный код product :: Num a => Rec1 f a -> a Исходный код | |
| (Foldable f, Foldable g) => Foldable (Product f g) Исходный код | С версии: base-4.9.0.0 |
Определено в Data.Functor.Product Методыfold :: Monoid m => Product f g m -> m Источник foldMap :: Monoid m => (a -> m) -> Product f g a -> m Источник foldMap' :: Monoid m => (a -> m) -> Product f g a -> m Источник foldr :: (a -> b -> b) -> b -> Product f g a -> b Источник foldr' :: (a -> b -> b) -> b -> Product f g a -> b Источник foldl :: (b -> a -> b) -> b -> Product f g a -> b Источник foldl' :: (b -> a -> b) -> b -> Product f g a -> b Источник foldr1 :: (a -> a -> a) -> Product f g a -> a Источник foldl1 :: (a -> a -> a) -> Product f g a -> a Источник toList :: Product f g a -> [a] Источник null :: Product f g a -> Bool Источник length :: Product f g a -> Int Источник elem :: Eq a => a -> Product f g a -> Bool Источник maximum :: Ord a => Product f g a -> a Источник minimum :: Ord a => Product f g a -> a Источник | |
| (Foldable f, Foldable g) => Foldable (Sum f g) Источник | С момента: base-4.9.0.0 |
Определено в Data.Functor.Sum Методыfold :: Monoid m => Sum f g m -> m Исходный код foldMap :: Monoid m => (a -> m) -> Sum f g a -> m Исходный код foldMap' :: Monoid m => (a -> m) -> Sum f g a -> m Исходный код foldr :: (a -> b -> b) -> b -> Sum f g a -> b Исходный код foldr' :: (a -> b -> b) -> b -> Sum f g a -> b Исходный код foldl :: (b -> a -> b) -> b -> Sum f g a -> b Исходный код foldl' :: (b -> a -> b) -> b -> Sum f g a -> b Исходный код foldr1 :: (a -> a -> a) -> Sum f g a -> a Исходный код foldl1 :: (a -> a -> a) -> Sum f g a -> a Исходный код toList :: Sum f g a -> [a] Исходный код null :: Sum f g a -> Bool Исходный код length :: Sum f g a -> Int Исходный код elem :: Eq a => a -> Sum f g a -> Bool Исходный код maximum :: Ord a => Sum f g a -> a Исходный код minimum :: Ord a => Sum f g a -> a Исходный код sum :: Num a => Sum f g a -> a Исходный код product :: Num a => Sum f g a -> a Исходный код | |
| (Foldable f, Foldable g) => Foldable (f :*: g) Исходный код | С момента: base-4.9.0.0 |
Определено в GHC.Internal.Data.Foldable Методыfold :: Monoid m => (f :*: g) m -> m Исходный код foldMap :: Monoid m => (a -> m) -> (f :*: g) a -> m Исходный код foldMap' :: Monoid m => (a -> m) -> (f :*: g) a -> m Исходный код foldr :: (a -> b -> b) -> b -> (f :*: g) a -> b Исходный код foldr' :: (a -> b -> b) -> b -> (f :*: g) a -> b Исходный код foldl :: (b -> a -> b) -> b -> (f :*: g) a -> b Исходный код foldl' :: (b -> a -> b) -> b -> (f :*: g) a -> b Исходный код foldr1 :: (a -> a -> a) -> (f :*: g) a -> a Исходный код foldl1 :: (a -> a -> a) -> (f :*: g) a -> a Исходный код toList :: (f :*: g) a -> [a] Исходный код null :: (f :*: g) a -> Bool Исходный код length :: (f :*: g) a -> Int Исходный код elem :: Eq a => a -> (f :*: g) a -> Bool Исходный код maximum :: Ord a => (f :*: g) a -> a Исходный код minimum :: Ord a => (f :*: g) a -> a Исходный код sum :: Num a => (f :*: g) a -> a Исходный код product :: Num a => (f :*: g) a -> a Исходный код | |
| (Foldable f, Foldable g) => Foldable (f :+: g) Исходный код | С версии: base-4.9.0.0 |
Определено в GHC.Internal.Data.Foldable Методыfold :: Моноид m => (f :+: g) m -> m Исходный код foldMap :: Моноид m => (a -> m) -> (f :+: g) a -> m Исходный код foldMap' :: Моноид m => (a -> m) -> (f :+: g) a -> m Исходный код foldr :: (a -> b -> b) -> b -> (f :+: g) a -> b Исходный код foldr' :: (a -> b -> b) -> b -> (f :+: g) a -> b Исходный код foldl :: (b -> a -> b) -> b -> (f :+: g) a -> b Исходный код foldl' :: (b -> a -> b) -> b -> (f :+: g) a -> b Исходный код foldr1 :: (a -> a -> a) -> (f :+: g) a -> a Исходный код foldl1 :: (a -> a -> a) -> (f :+: g) a -> a Исходный код toList :: (f :+: g) a -> [a] Исходный код null :: (f :+: g) a -> Булево Исходный код length :: (f :+: g) a -> Целое Исходный код elem :: Eq a => a -> (f :+: g) a -> Булево Исходный код maximum :: Ord a => (f :+: g) a -> a Исходный код minimum :: Ord a => (f :+: g) a -> a Исходный код sum :: Num a => (f :+: g) a -> a Исходный код product :: Num a => (f :+: g) a -> a Исходный код | |
| Foldable (K1 i c :: Тип -> Тип) Исходный код | С момента: base-4.9.0.0 |
Определено в GHC.Internal.Data.Foldable Методыfold :: Monoid m => K1 i c m -> m Исходный код foldMap :: Monoid m => (a -> m) -> K1 i c a -> m Исходный код foldMap' :: Monoid m => (a -> m) -> K1 i c a -> m Исходный код foldr :: (a -> b -> b) -> b -> K1 i c a -> b Исходный код foldr' :: (a -> b -> b) -> b -> K1 i c a -> b Исходный код foldl :: (b -> a -> b) -> b -> K1 i c a -> b Исходный код foldl' :: (b -> a -> b) -> b -> K1 i c a -> b Исходный код foldr1 :: (a -> a -> a) -> K1 i c a -> a Исходный код foldl1 :: (a -> a -> a) -> K1 i c a -> a Исходный код toList :: K1 i c a -> [a] Исходный код null :: K1 i c a -> Bool Исходный код length :: K1 i c a -> Int Исходный код elem :: Eq a => a -> K1 i c a -> Bool Исходный код maximum :: Ord a => K1 i c a -> a Исходный код minimum :: Ord a => K1 i c a -> a Исходный код sum :: Num a => K1 i c a -> a Исходный код product :: Num a => K1 i c a -> a Исходный код | |
| (Foldable f, Foldable g) => Foldable (Compose f g) Исходный код | С момента: base-4.9.0.0 |
Определено в Data.Functor.Compose Методыfold :: Monoid m => Compose f g m -> m Источник foldMap :: Monoid m => (a -> m) -> Compose f g a -> m Источник foldMap' :: Monoid m => (a -> m) -> Compose f g a -> m Источник foldr :: (a -> b -> b) -> b -> Compose f g a -> b Источник foldr' :: (a -> b -> b) -> b -> Compose f g a -> b Источник foldl :: (b -> a -> b) -> b -> Compose f g a -> b Источник foldl' :: (b -> a -> b) -> b -> Compose f g a -> b Источник foldr1 :: (a -> a -> a) -> Compose f g a -> a Источник foldl1 :: (a -> a -> a) -> Compose f g a -> a Источник toList :: Compose f g a -> [a] Источник null :: Compose f g a -> Bool Источник length :: Compose f g a -> Int Источник elem :: Eq a => a -> Compose f g a -> Bool Источник maximum :: Ord a => Compose f g a -> a Источник minimum :: Ord a => Compose f g a -> a Источник | |
| (Foldable f, Foldable g) => Foldable (f :.: g) Источник | С момента: base-4.9.0.0 |
Определено в GHC.Internal.Data.Foldable Методыfold :: Monoid m => (f :.: g) m -> m Исходный код foldMap :: Monoid m => (a -> m) -> (f :.: g) a -> m Исходный код foldMap' :: Monoid m => (a -> m) -> (f :.: g) a -> m Исходный код foldr :: (a -> b -> b) -> b -> (f :.: g) a -> b Исходный код foldr' :: (a -> b -> b) -> b -> (f :.: g) a -> b Исходный код foldl :: (b -> a -> b) -> b -> (f :.: g) a -> b Исходный код foldl' :: (b -> a -> b) -> b -> (f :.: g) a -> b Исходный код foldr1 :: (a -> a -> a) -> (f :.: g) a -> a Исходный код foldl1 :: (a -> a -> a) -> (f :.: g) a -> a Исходный код toList :: (f :.: g) a -> [a] Исходный код null :: (f :.: g) a -> Bool Исходный код length :: (f :.: g) a -> Int Исходный код elem :: Eq a => a -> (f :.: g) a -> Bool Исходный код maximum :: Ord a => (f :.: g) a -> a Исходный код minimum :: Ord a => (f :.: g) a -> a Исходный код sum :: Num a => (f :.: g) a -> a Исходный код product :: Num a => (f :.: g) a -> a Исходный код | |
| Foldable f => Foldable (M1 i c f) Исходный код | С версии: base-4.9.0.0 |
Определено в GHC.Internal.Data.Foldable Методыfold :: Моноид m => M1 i c f m -> m Исходный код foldMap :: Моноид m => (a -> m) -> M1 i c f a -> m Исходный код foldMap' :: Моноид m => (a -> m) -> M1 i c f a -> m Исходный код foldr :: (a -> b -> b) -> b -> M1 i c f a -> b Исходный код foldr' :: (a -> b -> b) -> b -> M1 i c f a -> b Исходный код foldl :: (b -> a -> b) -> b -> M1 i c f a -> b Исходный код foldl' :: (b -> a -> b) -> b -> M1 i c f a -> b Исходный код foldr1 :: (a -> a -> a) -> M1 i c f a -> a Исходный код foldl1 :: (a -> a -> a) -> M1 i c f a -> a Исходный код toList :: M1 i c f a -> [a] Исходный код null :: M1 i c f a -> Булево Исходный код length :: M1 i c f a -> Целое Исходный код elem :: Eq a => a -> M1 i c f a -> Булево Исходный код maximum :: Ord a => M1 i c f a -> a Исходный код minimum :: Ord a => M1 i c f a -> a Исходный код sum :: Число a => M1 i c f a -> a Исходный код product :: Число a => M1 i c f a -> a Исходный код |
Специальные сдвинутые сложения
foldrM :: (Foldable t, Монадный m) => (a -> b -> m b) -> b -> t a -> m b Исходный код
Монадное сложение элементов структуры справа налево.
Учитывая структуру t с элементами (a, b, c, ..., x, y), результат сложения с операторной функцией f эквивалентен:
foldrM f z t = do
yy <- f y z
xx <- f x yy
...
bb <- f b cc
aa <- f a bb
return aa -- Just @return z@ when the structure is empty
Для Монады m, заданных двух функций f1 :: a -> m b и f2 :: b -> m c, их композиция по Клейсли (f1 >=> f2) :: a -> m c определяется следующим образом:
(f1 >=> f2) a = f1 a >>= f2
Другой способ понять foldrM заключается в том, что он эквивалентен применению к z композиции по Клейсли:
foldrM f z t = f y >=> f x >=> ... >=> f b >=> f a $ z
Моноидные эффекты foldrM выполняются справа налево, и, например, сложения бесконечных списков будут разветвляться.
Если на каком-то шаге оператор связывания (>>=) завершается (как, например, mzero в MonadPlus), оцененные эффекты будут взяты из хвоста последовательности элементов. Если вам нужно оценить моноидные эффекты слева направо или, возможно, завершиться после начальной последовательности элементов, вам нужно использовать foldlM вместо этого.
Если моноидные эффекты не завершаются, внешнее применение f к левому крайнему элементу a, так что, игнорируя эффекты, результат выглядит как правое сложение:
a `f` (b `f` (c `f` (... (x `f` (y `f` z))))).
Примеры
Основное использование:
>>> let f i acc = do { print i ; return $ i : acc }
>>> foldrM f [] [0..3]
3
2
1
0
[0,1,2,3]
foldlM :: (Foldable t, Монадный m) => (b -> a -> m b) -> b -> t a -> m b Исходный код
Монадное сложение элементов структуры слева направо.
Учитывая структуру t с элементами (a, b, ..., w, x, y), результат сложения с операторной функцией f эквивалентен:
foldlM f z t = do
aa <- f z a
bb <- f aa b
...
xx <- f ww x
yy <- f xx y
return yy -- Just @return z@ when the structure is empty
Для Монады m, заданных двух функций f1 :: a -> m b и f2 :: b -> m c, их композиция по Клейсли (f1 >=> f2) :: a -> m c определяется следующим образом:
(f1 >=> f2) a = f1 a >>= f2
Другой способ понять foldlM заключается в том, что он эквивалентен применению к z композиции по Клейсли:
foldlM f z t =
flip f a >=> flip f b >=> ... >=> flip f x >=> flip f y $ z
Моноидные эффекты foldlM выполняются слева направо.
Если на каком-то шаге оператор связывания (>>=) завершается (как, например, mzero в MonadPlus ), оцененные эффекты будут взяты из начального сегмента последовательности элементов. Если вам нужно оценить моноидные эффекты справа налево или, возможно, завершиться после обработки хвоста последовательности элементов, вам нужно использовать foldrM вместо этого.
Если моноидные эффекты не завершаются, внешнее применение f к правому крайнему элементу y, так что, игнорируя эффекты, результат выглядит как левое сложение:
((((z `f` a) `f` b) ... `f` w) `f` x) `f` y
Примеры
Основное использование:
>>> let f a e = do { print e ; return $ e : a }
>>> foldlM f [] [0..3]
0
1
2
3
[3,2,1,0]
Действия сложения
Прикладные действия
traverse_ :: (Foldable t, Прикладной f) => (a -> f b) -> t a -> f () Исходный код
Преобразуйте каждый элемент структуры в Applicative действие, вычислите эти действия слева направо и игнорируйте результаты. Для версии, которая не игнорирует результаты, см. traverse.
traverse_ это то же самое, что и mapM_, но обобщено на Applicative действия.
Примеры
Основное использование:
>>> traverse_ print ["Hello", "world", "!"] "Hello" "world" "!"
for_ :: (Foldable t, Applicative f) => t a -> (a -> f b) -> f () Source
for_ является traverse_ со своими аргументами, перевернутыми местами. Для версии, которая не игнорирует результаты, см. for. Это forM_ обобщено на Applicative действия.
for_ похож на forM_, но обобщен на Applicative действия.
Примеры
Базовое использование:
>>> for_ [1..4] print 1 2 3 4
sequenceA_ :: (Foldable t, Applicative f) => t (f a) -> f () Source
Выполнить каждое действие в структуре слева направо и проигнорировать результаты. Для версии, которая не игнорирует результаты, см. sequenceA.
sequenceA_ похож на sequence_, но обобщен на Applicative действия.
Примеры
Базовое использование:
>>> sequenceA_ [print "Hello", print "world", print "!"] "Hello" "world" "!"
asum :: (Foldable t, Alternative f) => t (f a) -> f a Source
Сумма набора действий, используя (<|>), обобщение concat.
asum похож на msum, но обобщен на Alternative.
Примеры
Базовое использование:
>>> asum [Just "Hello", Nothing, Just "World"] Just "Hello"
Действия монады
mapM_ :: (Foldable t, Monad m) => (a -> m b) -> t a -> m () Source
Применить к каждому элементу структуры монадическое действие, выполнить эти действия слева направо и проигнорировать результаты. Для версии, которая не игнорирует результаты, см. mapM.
mapM_ похож на traverse_, но специализирован на монадических действиях.
forM_ :: (Foldable t, Monad m) => t a -> (a -> m b) -> m () Source
forM_ является mapM_ со своими аргументами, перевернутыми местами. Для версии, которая не игнорирует результаты, см. forM.
forM_ похож на for_, но специализирован на монадических действиях.
sequence_ :: (Foldable t, Monad m) => t (m a) -> m () Source
Выполнить каждое монадическое действие в структуре слева направо и проигнорировать результаты. Для версии, которая не игнорирует результаты, см. sequence.
sequence_ похож на sequenceA_, но специализирован на монадических действиях.
msum :: (Foldable t, MonadPlus m) => t (m a) -> m a Source
Сумма набора действий, используя (<|>), обобщение concat.
msum похож на asum, но специализирован на MonadPlus.
Примеры
Базовое использование, используя MonadPlus экземпляр для Maybe:
>>> msum [Just "Hello", Nothing, Just "World"] Just "Hello"
Специализированные свертки
concat :: Foldable t => t [a] -> [a] Source
Конкатенация всех элементов контейнера списков.
Примеры
Базовое использование:
>>> concat (Just [1, 2, 3]) [1,2,3]
>>> concat (Left 42) []
>>> concat [[1, 2, 3], [4, 5], [6], []] [1,2,3,4,5,6]
concatMap :: Foldable t => (a -> [b]) -> t a -> [b] Source
Применить функцию ко всем элементам контейнера и конкатенировать полученные списки.
Примеры
Базовое использование:
>>> concatMap (take 3) [[1..], [10..], [100..], [1000..]] [1,2,3,10,11,12,100,101,102,1000,1001,1002]
>>> concatMap (take 3) (Just [1..]) [1,2,3]
and :: Foldable t => t Bool -> Bool Source
and возвращает конъюнкцию контейнера значений типа Bool. Для получения результата True, контейнер должен быть конечным; False, однако, результат получается из False значения, конечного по отношению к левому концу.
Примеры
Базовое использование:
>>> and [] True
>>> and [True] True
>>> and [False] False
>>> and [True, True, False] False
>>> and (False : repeat True) -- Infinite list [False,True,True,True,... False
>>> and (repeat True) * Hangs forever *
or :: Foldable t => t Bool -> Bool Source
or возвращает дизъюнкцию контейнера значений типа Bool. Для получения результата False, контейнер должен быть конечным; True, однако, результат получается из True значения, конечного по отношению к левому концу.
Примеры
Базовое использование:
>>> or [] False
>>> or [True] True
>>> or [False] False
>>> or [True, True, False] True
>>> or (True : repeat False) -- Infinite list [True,False,False,False,... True
>>> or (repeat False) * Hangs forever *
any :: Foldable t => (a -> Bool) -> t a -> Bool Source
Определяет, удовлетворяет ли какое-либо из элементов структуры предикату.
Примеры
Базовое использование:
>>> any (> 3) [] False
>>> any (> 3) [1,2] False
>>> any (> 3) [1,2,3,4,5] True
>>> any (> 3) [1..] True
>>> any (> 3) [0, -1..] * Hangs forever *
all :: Foldable t => (a -> Bool) -> t a -> Bool Source
Определяет, удовлетворяют ли все элементы структуры предикату.
Примеры
Базовое использование:
>>> all (> 3) [] True
>>> all (> 3) [1,2] False
>>> all (> 3) [1,2,3,4,5] False
>>> all (> 3) [1..] False
>>> all (> 3) [4..] * Hangs forever *
maximumBy :: Foldable t => (a -> a -> Ordering) -> t a -> a Source
Наибольший элемент непустой структуры относительно заданной функции сравнения. Порядок структуры используется как критерий развязки ничьей: если наибольших элементов несколько, выбирается самый правый из них.
Примеры
Базовое использование:
>>> maximumBy (compare `on` length) ["Hello", "World", "!", "Longest", "bar"] "Longest"
ПРЕДУПРЕЖДЕНИЕ: Эта функция частичная для, возможно, пустых структур, таких как списки.
minimumBy :: Foldable t => (a -> a -> Ordering) -> t a -> a Исходный код
Наименьший элемент непустой структуры относительно заданной функции сравнения. Порядок структуры используется для разделения связей: если есть несколько наименьших элементов, выбирается самый левый из них.
Примеры
Базовое использование:
>>> minimumBy (compare `on` length) ["Hello", "World", "!", "Longest", "bar"] "!"
ПРЕДУПРЕЖДЕНИЕ: Эта функция частичная для, возможно, пустых структур, таких как списки.
Поиск
notElem :: (Foldable t, Eq a) => a -> t a -> Bool infix 4 Исходный код
notElem является отрицанием elem.
Примеры
Базовое использование:
>>> 3 `notElem` [] True
>>> 3 `notElem` [1,2] True
>>> 3 `notElem` [1,2,3,4,5] False
Для бесконечных структур, notElem завершается, если значение существует на конечном расстоянии слева от структуры:
>>> 3 `notElem` [1..] False
>>> 3 `notElem` ([4..] ++ [3]) * Hangs forever *
find :: Foldable t => (a -> Bool) -> t a -> Maybe a Исходный код
Функция find принимает предикат и структуру и возвращает самый левый элемент структуры, соответствующий предикату, или Nothing если такого элемента нет.
Примеры
Базовое использование:
>>> find (> 42) [0, 5..] Just 45
>>> find (> 12) [1..7] Nothing
Обзор
Класс Foldable обобщает некоторые общие функции Data.List на структуры, которые могут быть приведены к суммарному значению по одному элементу за раз.
Левые и правые слияния
Вклад каждого элемента в конечный результат комбинируется с аккумулятором с помощью подходящего оператора. Оператор может быть явно задан вызывающим абонентом, как в foldr, или может быть неявным, как в length. В случае foldMap, вызывающий абонент предоставляет функцию, отображающую каждый элемент в подходящий Monoid, что позволяет объединить вклады по элементам с помощью функции mappend моноида.
Ключевое различие заключается между левоассоциативными и правоассоциативными слияниями:
- При левоассоциативных слияниях аккумулятор является частичным слиянием элементов, которые предшествуют текущему элементу, и передается оператору в качестве первого (левого) аргумента. Наружное применение оператора объединяет вклад последнего элемента структуры с вкладами всех его предшественников.
- При правоассоциативных слияниях аккумулятор является частичным слиянием элементов, которые следуют за текущим элементом, и передается оператору в качестве второго (правого) аргумента. Наружное применение оператора объединяет вклад первого элемента структуры с вкладами всех его преемников.
Эти два типа слияний типизируются левоассоциативным строгим foldl' и правоассоциативным ленивым foldr.
foldl' :: Foldable t => (b -> a -> b) -> b -> t a -> b foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b
Пример использования:
>>> foldl' (+) 0 [1..100] 5050 >>> foldr (&&) True (List.repeat False) False
Первый аргумент обоих – это явный оператор, который объединяет вклад элемента структуры с частичным слиянием, соответственно, либо предшествующих, либо последующих элементов структуры.
Второй аргумент обоих – это начальное значение аккумулятора z типа b. Это результат слияния, когда структура пуста. Когда структура непуста, это значение аккумулятора, объединённое с первым элементом в левоассоциативных слияниях, или с последним элементом в правоассоциативных слияниях.
Третий и последний аргумент – это структура Foldable содержащая элементы (a, b, c, …).
-
foldl'принимает аргумент оператора вида:f :: b -- accumulated fold of the initial elements -> a -- current element -> b -- updated fold, inclusive of current element
Если последний элемент структуры –
y, результат слияния:g y . … . g c . g b . g a $ z where g element !acc = f acc element
Поскольку
foldl'строг по отношению к аккумулятору, это всегда строгое сокращение без возможности раннего возврата или промежуточных результатов. Структура должна быть конечной, так как результат не возвращается, пока не будет обработан последний элемент. Преимущество строгости – эффективность использования памяти: конечный результат может быть вычислен без хранения потенциально глубокого стека ленивых промежуточных результатов. -
foldrпринимает аргумент оператора вида:f :: a -- current element -> b -- accumulated fold of the remaining elements -> b -- updated fold, inclusive of current element
результат слияния:
f a . f b . f c . … $ z
Если каждый вызов
fдля текущего элементаe, (указанного ниже как(f e)) возвращает структуру, в которой её второй аргумент захвачен в лениво вычисляемой компоненте, то слияние оставшихся элементов доступно вызывающему абонентуfoldrв виде ожидающего вычисления (thunk), которое вычисляется только тогда, когда эта компонента оценивается.В противном случае, если какой-либо из
(f e)игнорирует свой второй аргумент, слияние останавливается на этом, и оставшиеся элементы не используются. В результате,foldrхорошо подходит для определения как рекурсивных, так и краткозамкнутых редукций.Когда оператор всегда строг по отношению к своему второму аргументу,
foldl'обычно лучше, чемfoldr. Когдаfoldrвызывается со строгим оператором, вычисление не может начаться, пока не будет достигнут последний элемент, к этому моменту в памяти может быть построен глубокий стек ожидающих приложений функций.
Ожидание эффективной итерации слева направо
Структуры Foldable обычно ожидаются как эффективно итерируемые слева направо. Итерация справа налево может быть значительно более дорогостоящей или даже невозможной (например, с бесконечными списками). Текст в разделах, которые указывают на различия в производительности между левоассоциативными и правоассоциативными слияниями, предполагает левосторонние структуры, в которых итерация слева направо дешевле, чем справа налево.
В конечных структурах, для которых последовательность справа налево не менее эффективна, чем слева направо, нет неявного различия в производительности между левоассоциативными и правоассоциативными слияниями. Если экземпляр структуры Foldable использует эту симметрию, чтобы также сделать строгие правые слияния эффективными с точки зрения памяти, а ленивые левые слияния рекурсивными, достаточно только выбрать для данной задачи строгий или ленивый метод.
Экземпляры Foldable для симметричных структур должны стремиться предоставить одинаково эффективные левоассоциативные и правоассоциативные интерфейсы. Основные ограничения:
- Ленивые методы
fold,foldMapиtoListне имеют правоассоциативных аналогов. - Строгий метод
foldMap'не имеет левоассоциативного аналога.
Таким образом, для некоторых структур Foldable foldr' столь же эффективен, как foldl' для строгого сокращения, а foldl может быть так же уместен для рекурсивных слияний, как и foldr.
Наконец, в некоторых менее распространённых структурах (например, списках с добавлением в конец snoc) итерации справа налево эффективнее, чем слева направо. Такие структуры плохо подходят для экземпляра Foldable и, возможно, лучше всего обрабатываются через свои специфичные для типа интерфейсы. Если тем не менее предоставляется экземпляр Foldable , материал в следующих разделах также применим к ним, заменив каждый метод на метод с противоположной ассоциативностью (если доступен) и поменяв порядок аргументов оператора слияния.
Возможно, придётся уделить особое внимание строгости оператора слияния, когда его строгость отличается между первым и вторым аргументами. Например, в то время как (+) ожидается, что будет коммутативным и строгим по отношению к обоим аргументам, оператор конкатенации списков (++) не является коммутативным и строг только по отношению к начальному конструктору первого аргумента. Слияние:
myconcat xs = foldr (\a b -> a ++ b) [] xs
существенно дешевле (линейно по отношению к длине потребляемой части конечного списка, таким образом, например, постоянное время/память для только первого элемента), чем:
revconcat xs = foldr (\a b -> b ++ a) [] xs
в котором общая стоимость увеличивается как с количеством объединяемых списков, так и с количеством в конечном итоге потреблённых элементов. Более эффективный способ объединения списков в обратном порядке – использовать:
revconcat = foldr (++) [] . reverse
Рекурсивное и корекурсивное сокращение
Как наблюдалось в описании выше левых и правых слияний, существуют три основных способа, которыми структура может быть сведена к суммарному значению:
- Рекурсивное сокращение, которое строго в отношении всех элементов структуры. Это создает единственный конечный результат только после обработки всей структуры входных данных, и поэтому входные данные должны быть конечными.
- Корекурсия, которая выдает промежуточные результаты по мере обнаружения дополнительных элементов входных данных. Ленивая обработка оставшихся элементов делает промежуточные результаты доступными еще до обработки остальной части входных данных. Входные данные могут быть неограниченными, и вызывающая сторона может остановить обработку промежуточных результатов рано.
- Короткое замыкание сокращение, которое проверяет некоторую начальную последовательность элементов входных данных, но останавливается, как только выполняется условие завершения, возвращая конечный результат, основанный только на элементах, рассмотренных до этого момента. Остальные элементы не рассматриваются. Входные данные обычно должны быть конечными, потому что в противном случае условие завершения может никогда не быть выполнено.
Является ли свёртка рекурсивной, корекурсивной или с коротким замыканием, может зависеть как от выбранного метода выполнения свёртки, так и от оператора, переданного этому методу (который может быть неявным, как в методе mappend экземпляра моноида).
Также существуют гибридные случаи, когда выбранный метод и/или оператор не подходят для поставленной задачи, что приводит к свёртке, которая не выдает промежуточные результаты до обработки всей входной информации или не строго оценивает результаты по ходу, делегируя всю работу оценке большого конечного тука. Такие случаи следует избегать, либо выбирая более подходящий метод Foldable, либо подгоняя оператор к выбранному методу.
Различие между этими типами свёртки имеет решающее значение, как при принятии решения о том, какой метод Foldable использовать для эффективного выполнения сокращения, так и при написании экземпляров Foldable для новых структур. Ниже приводится более подробный обзор каждого типа.
Строгие рекурсивные свёртки
Общие примеры строгого рекурсивного сокращения — это различные функции агрегирования, такие как sum, product, length, а также более сложные сводки, такие как подсчёт частоты. Эти функции возвращают только одно значение после обработки всей структуры входных данных. В таких случаях ленивая обработка хвоста структуры входных данных не только не нужна, но и неэффективна. Поэтому эти и подобные свёртки следует реализовывать в терминах строгих левоассоциативных методов Foldable (обычно foldl') для эффективного сокращения в постоянном пространстве.
Обратно, реализация Foldable для новой структуры должна гарантировать, что foldl' фактически выполняет строгое левоассоциативное сокращение.
Метод foldMap' является частным случаем foldl', в котором начальное значение аккумулятора — mempty, а оператор — mappend . f, где f отображает каждый элемент входных данных в Monoid в вопросе. Поэтому foldMap' является подходящим выбором практически при тех же условиях, что и foldl', и его реализация для данной структуры Foldable также должна быть строгим левоассоциативным сокращением.
Хотя приведенные ниже примеры не являются обязательно наиболее оптимальными определениями целевых функций, они все представляют собой случаи, в которых foldMap' намного более уместен (а также более эффективен), чем ленивая свёртка foldMap.
length = getSum . foldMap' (const (Sum 1)) sum = getSum . foldMap' Sum product = getProduct . foldMap' Product
[ Фактические значения по умолчанию используют принуждения для оптимизации getSum и getProduct. ]
Список строгих функций
Полный список строгих рекурсивных функций в этом модуле:
-
При условии, что оператор строго в отношении своего левого аргумента:
foldl' :: Foldable t => (b -> a -> b) -> b -> t a -> b
-
При условии, что
mappendстрого в отношении своего левого аргумента:foldMap' :: (Foldable t, Monoid m) => (a -> m) -> t a -> m
-
При условии, что экземпляр определён правильно:
length :: Foldable t => t a -> Int sum :: (Foldable t, Num a) => t a -> a product :: (Foldable t, Num a) => t a -> a maximum :: (Foldable t, Ord a) => t a -> a minimum :: (Foldable t, Ord a) => t a -> a maximumBy :: Foldable t => (a -> a -> Ordering) -> t a -> a minimumBy :: Foldable t => (a -> a -> Ordering) -> t a -> a
Ленивые корекурсивные свёртки
Общие примеры ленивого корекурсивного сокращения — это функции, которые отображают и сплющивают структуру в ленивый поток значений результата, т. е. итератор по преобразованным элементам входных данных. В таких случаях важно выбрать метод Foldable который ленив в отношении хвоста структуры, например, foldr (или foldMap, если результат Monoid имеет ленивый mappend как, например, у ByteString Builders).
Обратно, реализация foldr для структуры, которая может вместить большое (и, возможно, неограниченное) количество элементов, ожидается ленивой в отношении хвоста входных данных, что позволяет операторам, которые ленивы в отношении аккумулятора, выводить промежуточные результаты по частям. Такие свёртки являются правоассоциативными, и хвост потока возвращается как лениво вычисляемая часть результата (элемент кортежа или какой-либо другой нестрогой конструкции, например, конструкция (:) для списков).
Функция toList ниже лениво преобразует структуру Foldable в список. Обратите внимание, что это преобразование может быть необратимым, например, для контейнера с ключами (Map, HashMap, …) выходной поток содержит только значения, а не ключи. Обратимые преобразования в/из списков пар (key,
value) обычно доступны в модулях для конкретных типов контейнеров.
toList = foldr (:) []
Более сложным примером является конкатенация списка списков, выраженная как вложенная правая свёртка (обходя (++)). Мы можем проверить, что определение действительно лениво, выполнив свёртку бесконечного списка списков и взяв начальный сегмент.
>>> myconcat = foldr (\x z -> foldr (:) z x) [] >>> List.take 15 $ myconcat $ List.map (\i -> [0..i]) [0..] [0,0,1,0,1,2,0,1,2,3,0,1,2,3,4]
Конечно, в этом случае другой способ достижения того же результата — это генератор списка:
myconcat xss = [x | xs <- xss, x <- xs]
Список ленивых функций
Полный список ленивых корекурсивных функций в этом модуле:
-
При условии, что функция сокращения ленива в отношении своего второго аргумента (в противном случае лучше использовать строгое рекурсивное сокращение):
foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b foldr1 :: Foldable t => (a -> a -> a) -> t a -> a
-
При условии, что
Monoidmappendленива в отношении своего второго аргумента (в противном случае лучше использовать строгое рекурсивное сокращение):fold :: Foldable t => Monoid m => t m -> m foldMap :: Foldable t => Monoid m => (a -> m) -> t a -> m
-
При условии, что экземпляр определён правильно:
toList :: Foldable t => t a -> [a] concat :: Foldable t => t [a] -> [a] concatMap :: Foldable t => (a -> [b]) -> t a -> [b]
Свёртки с коротким замыканием
Примеры сокращения с коротким замыканием включают различные булевы предикаты, проверяющие, удовлетворяют ли некоторые или все элементы структуры заданному условию. Поскольку они не обязательно потребляют весь список, они обычно используют foldr с оператором, который условно строго в отношении своего второго аргумента. Как только выполняется условие завершения, второй аргумент (хвост структуры входных данных) игнорируется. Результат не возвращается, пока это не произойдёт.
Ключевой отличительной чертой этих свёрок является условность строгости во втором аргументе; он иногда вычисляется, а иногда нет.
Самый простой (вырожденный случай) из них — это null, определяющий, пуста ли структура или нет. Для этого нужно только посмотреть на первый элемент, и только в той мере, существует ли он, а не его значение. В этом случае завершение гарантировано, и структуры входных данных бесконечной длины подходят.
Естественно, его стандартное определение использует ленивую свёртку foldr.
null = foldr (\_ _ -> False) True
Более общий пример — any, который применяет предикат к каждому элементу входных данных по очереди, пока не найдёт первый элемент, для которого предикат истиннен, после чего он возвращает успех. Если в бесконечном потоке входных данных предикат ложен для всех элементов, any не завершит работу, но, поскольку он работает в постоянном пространстве, он, как правило, не выйдет из памяти, он просто будет зацикливаться вечно.
Список функций с коротким замыканием
Полный список свёртки с коротким замыканием в этом модуле:
-
Свёртки булевых предикатов. Эти функции строго проверяют элементы до тех пор, пока не будет выполнено условие, но затем возвращают результат, игнорируя остальную часть (ленивые в отношении хвоста). Они могут зацикливаться бесконечно, если входные данные неограничены, и ни один элемент не удовлетворяет условию завершения.
null :: Foldable t => t a -> Bool elem :: Foldable t => Eq a => a -> t a -> Bool notElem :: (Foldable t, Eq a) => a -> t a -> Bool and :: Foldable t => t Bool -> Bool or :: Foldable t => t Bool -> Bool find :: Foldable t => (a -> Bool) -> t a -> Maybe a any :: Foldable t => (a -> Bool) -> t a -> Bool all :: Foldable t => (a -> Bool) -> t a -> Bool
-
Многие экземпляры
(<|>)(например, экземплярMaybe) являются условно ленивыми и используют или не используют свой второй аргумент в зависимости от значения первого. Они используются со свёртками ниже, которые завершаются как можно раньше, но в противном случае, как правило, продолжают работу. Некоторые экземпляры (например, для List) всегда строгие, но результат ленив в хвосте вывода, так чтоasumдля списка списков на самом деле является корекурсивным. Эти свёртки определены в терминахfoldr.asum :: (Foldable t, Alternative f) => t (f a) -> f a msum :: (Foldable t, MonadPlus m) => t (m a) -> m a
-
Точно так же оператор
(*>)в некоторыхApplicativeфункторах и(>>)в некоторых монадах являются условно ленивыми и могут прервать цепочку вычислений. Нижеприведённые свёртки будут завершаться как можно раньше, но даже бесконечные циклы могут быть продуктивными здесь, когда они вычисляются исключительно ради своего потока побочных эффектов IO. См. Data.Traversable для обсуждения связанных функций.traverse_ :: (Foldable t, Applicative f) => (a -> f b) -> t a -> f () for_ :: (Foldable t, Applicative f) => t a -> (a -> f b) -> f () sequenceA_ :: (Foldable t, Applicative f) => t (f a) -> f () mapM_ :: (Foldable t, Monad m) => (a -> m b) -> t a -> m () forM_ :: (Foldable t, Monad m) => t a -> (a -> m b) -> m () sequence_ :: (Foldable t, Monad m) => t (m a) -> m ()
-
Наконец, есть ещё один частный случай,
foldlM.foldlM :: (Foldable t, Monad m) => (b -> a -> m b) -> b -> t a -> m b
Последовательность монадных эффектов идёт слева направо. Если на каком-то шаге оператор связывания
(>>=)прерывается (как, например,mzeroсMonadPlus, или исключение сMonadThrow, и т. д.), то вычисленные эффекты будут из начальной части последовательности элементов.:set -XBangPatterns import Control.Monad import Control.Monad.Trans.Class import Control.Monad.Trans.Maybe import Data.Foldable let f !_ e = when (e > 3) mzero >> lift (print e) runMaybeT $ foldlM f () [0..]
0 1 2 3 Nothing
Контрастируйте это с
foldrM, которая упорядочивает монадные эффекты справа налево и поэтому расходится при свёртке неограниченной структуры входных данных, никогда не имея возможности прервать свёртку.let f e _ = when (e > 3) mzero >> lift (print e) runMaybeT $ foldrM f () [0..]
…зависает…
Когда структура конечна,
foldrMвыполняет монадные эффекты справа налево, возможно, прерывая свёртку после обработки хвостовой части последовательности элементов.let f e _ = when (e < 3) mzero >> lift (print e) runMaybeT $ foldrM f () [0..5]
5 4 3 Nothing
Гибридные свёртки
Нижеприведенные свёртки не являются ни строгими сокращениями, которые производят окончательный ответ в постоянном пространстве, ни ленивыми корекурсиями, и поэтому имеют ограниченную применимость. Они имеют специализированные применения, но лучше их избегать, если в этом нет уверенности.
foldr' :: Foldable t => (a -> b -> b) -> b -> t a -> b foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b foldl1 :: Foldable t => (a -> a -> a) -> t a -> a foldrM :: (Foldable t, Monad m) => (a -> b -> m b) -> b -> t a -> m b
Левые ленивые свёртки (используемые корекурсивно) и foldrM (используемые для упорядочения действий справа налево) могут быть эффективными в структурах, чьи экземпляры Foldable используют эффективный итератор справа налево для вычисления ленивых левых свёрок снаружи внутрь с правого элемента.
Строгая foldr' наименее вероятно будет полезна, так как структуры, поддерживающие упорядочение только справа налево, не очень распространены.
Генеративная рекурсия
До сих пор мы не обсуждали генеративную рекурсию. В отличие от рекурсивного сокращения или корекурсии, вместо обработки последовательности элементов, уже находящихся в памяти, генеративная рекурсия предполагает получение, возможно, неограниченной последовательности значений из начального значения-затравки. Каноническим примером этого является unfoldr для списков, с вариантами, доступными для векторов и различных других структур.
Ключевая проблема со списками, когда они используются генеративно как итераторы, а не как контейнеры для бедных (см. [1]), заключается в том, что такие итераторы потребляют память, когда используются более одного раза. Однократное прохождение списка как итератора будет выполняться в постоянном объёме памяти, но как только список сохраняется для повторного использования, вся последовательность его элементов хранится в памяти, а второе прохождение считывает копию, а не генерирует элементы заново. Иногда лучше вычислять элементы заново, чем запоминать список.
Запоминание происходит, потому что встроенный список Haskell [] представлен как данные, либо пустые, либо ячейка cons, содержащая первый элемент и хвост списка. Класс Foldable позволяет использовать альтернативное представление итераторов как функций, которые принимают оператор и начальное значение аккумулятора и возвращают итоговый результат.
Пакет fmlist использует этот подход, представляя список через его foldMap действие.
Ниже мы реализуем аналогичную структуру данных, используя представление, основанное на foldr. Это пример кодирования Чёрча (названного в честь Альonzo Church, изобретателя лямбда-исчисления).
{-# LANGUAGE RankNTypes #-}
newtype FRList a = FR { unFR :: forall b. (a -> b -> b) -> b -> b }
Поле unFR этого типа по существу является его методом foldr со списком в качестве первого, а не последнего аргумента. Таким образом, мы сразу получаем экземпляр Foldable (и функцию toList отображающую FRList в обычный список).
instance Foldable FRList where
foldr f z l = unFR l f z
-- With older versions of @base@, also define sum, product, ...
-- to ensure use of the strict 'foldl''.
-- sum = foldl' (+) 0
-- ...
Мы можем преобразовать обычный список в FRList с помощью:
fromList :: [a] -> FRList a fromList as = FRList $ \ f z -> foldr f z as
Однако, повторное использование FRList, полученного таким образом, обычно приводит к запоминанию основной последовательности элементов. Вместо этого мы можем определить FRList термины непосредственно:
-- | Immediately return the initial accumulator
nil :: FRList a
nil = FRList $ \ _ z -> z
{-# INLINE nil #-}
-- | Fold the tail to use as an accumulator with the new initial element
cons :: a -> FRList a -> FRList a
cons a l = FRList $ \ f z -> f a (unFR l f z)
{-# INLINE cons #-}
Более важно, что мы также можем напрямую определить ключевой строительный блок для генеративной рекурсии:
-- | Generative recursion, dual to `foldr`.
unfoldr :: (s -> Maybe (a, s)) -> s -> FRList a
unfoldr g s0 = FR generate
where generate f z = loop s0
where loop s | Just (a, t) <- g s = f a (loop t)
| otherwise = z
{-# INLINE unfoldr #-}
Что, например, может быть специализировано для числовых диапазонов:
-- | Generate a range of consecutive integral values.
range :: (Ord a, Integral a) => a -> a -> FRList a
range lo hi =
unfoldr (\s -> if s > hi then Nothing else Just (s, s+1)) lo
{-# INLINE range #-}
Программа ниже, при компиляции с оптимизацией:
main :: IO ()
main = do
let r :: FRList Int
r = range 1 10000000
in print (sum r, length r)
выводит ожидаемый результат без заметной работы сборщика мусора, несмотря на повторное использование FRList термина r.
(50000005000000,10000000)
52,120 bytes allocated in the heap
3,320 bytes copied during GC
44,376 bytes maximum residency (1 sample(s))
25,256 bytes maximum slop
3 MiB total memory in use (0 MB lost due to fragmentation)
Слабая нормальная форма FRList — это абстракция лямбды, а не значение данных, и повторное использование не приводит к запоминанию. Повторное использование итератора выше несколько искусственно, при вычислении нескольких сгибов над общим списком, вы обычно должны пройти по списку только один раз. Цель состоит в том, чтобы продемонстрировать, что отдельные вычисления sum и length выполняются эффективно в постоянном объёме памяти, несмотря на повторное использование. Это не было бы так с списком [1..10000000].
Однако это искусственно упрощённое сокращение. Чаще всего, вероятно, будут какие-то выделения памяти во внутреннем цикле, но временное хранилище будет собираться мусором по мере необходимости, и общее использование памяти останется умеренным и не будет масштабироваться с размером списка.
Если мы вернёмся к встроенным спискам (т.е. []), но избежим повторного использования, выполнив сокращение за один проход, как показано ниже:
data PairS a b = P !a !b -- We define a strict pair datatype
main :: IO ()
main = do
let l :: [Int]
l = [1..10000000]
in print $ average l
where
sumlen :: PairS Int Int -> Int -> PairS Int Int
sumlen (P s l) a = P (s + a) (l + 1)
average is =
let (P s l) = foldl' sumlen (P 0 0) is
in (fromIntegral s :: Double) / fromIntegral l
результат снова получается в постоянном объёме памяти:
5000000.5
102,176 bytes allocated in the heap
3,320 bytes copied during GC
44,376 bytes maximum residency (1 sample(s))
25,256 bytes maximum slop
3 MiB total memory in use (0 MB lost due to fragmentation)
(и, фактически, быстрее, чем с FRList на небольшой фактор).
Структура списка [] работает как эффективный итератор, когда используется только один раз. Когда утечки памяти из-за повторного использования списков не влияют, и/или запоминание на самом деле желательно, стандартная реализация списка, вероятно, будет быстрее. Это не предложение заменить все ваши использования [] генеративной альтернативой.
Тип FRList можно было бы дополнительно расширить экземплярами Functor, Applicative, Monad, Alternative, и т.д., и тогда он мог бы предоставить полностью функциональный тип списка, оптимизированный для повторного использования без утечек памяти. Однако, если всё, что требуется, это экономичная с точки зрения памяти, дружественная к повторному использованию итерация, меньше, возможно, больше, и просто Foldable может быть достаточно.
Избегание сгибов с несколькими проходами
В приложениях, где вы хотите вычислить составную функцию структуры, которая требует более одного агрегата в качестве входных данных, как правило, лучше вычислить все агрегаты за один проход, а не проходить по одной и той же структуре многократно.
Пакет foldl реализует прочный общий фреймворк для работы с этой ситуацией. Если вы решите сделать это сами, с небольшими предосторожностями, самые простые случаи несложно обработать напрямую. Вам просто нужно накапливать отдельные агрегаты как строгие компоненты одного типа данных, а затем применить финальное преобразование, чтобы извлечь составной результат. Например, вычисление среднего значения требует вычисления как sum , так и length структуры (непустой) и деления суммы на длину:
import Data.Foldable (foldl')
data PairS a b = P !a !b -- We define a strict pair datatype
-- | Compute sum and length in a single pass, then reduce to the average.
average :: (Foldable f, Fractional a) => f a -> a
average xs =
let sumlen (P s l) a = P (s + a) (l + 1 :: Int)
(P s l) = foldl' sumlen (P 0 0) xs
in s / fromIntegral l
Приведённый выше пример несколько искусственный, некоторые структуры отслеживают свою длину внутри и могут вернуть её за O(1) времени, поэтому этот конкретный рецепт для средних значений не всегда самый эффективный. В целом, составные агрегатные функции больших структур выигрывают от однократного сокращения. Это особенно верно, когда повторное использование списка и запоминание его элементов таким образом избегаются.
Определение экземпляров
Для многих структур разумные экземпляры Foldable могут быть получены автоматически, включив расширение GHC DeriveFoldable. Когда это работает, обычно нет необходимости определять пользовательский экземпляр вручную. Хотя в некоторых случаях можно получить немного более быстрый настроенный код, требуется осторожность, чтобы не создавать медленный код или код, который недостаточно ленив, строг или правилен.
Вручную созданные экземпляры могут ограничиться определением только одного из foldr или foldMap. Все остальные методы имеют определения по умолчанию в терминах одного из них. Определения по умолчанию имеют ожидаемую строгость и ожидаемые асимптотические временные и пространственные затраты, с учётом небольших постоянных факторов. Если вы выбираете ручную настройку, рекомендуется производить бенчмаркинг, чтобы посмотреть, делаете ли вы лучше, чем реализация по умолчанию, а также тщательные тесты, чтобы убедиться, что пользовательские методы правильны.
Ниже мы создаём экземпляр Foldable для типа данных, представляющего бинарное дерево (конечное) с обходом в глубину.
>>> data Tree a = Empty | Leaf a | Node (Tree a) a (Tree a)
Подходящий экземпляр будет:
>>> :{
instance Foldable Tree where
foldr f z Empty = z
foldr f z (Leaf x) = f x z
foldr f z (Node l k r) = foldr f (f k (foldr f z r)) l
:}
Случай Node — это правая свертка левого поддерева, начальное значение которого — правая свертка остальной части дерева.
Например, когда f является (:), все три случая возвращают непосредственное значение, соответственно z или ячейку cons, содержащую x или l, при этом остальная часть структуры, если таковая имеется, захвачена в ленивом туннеле. Это соответствует ожидаемому эффективному корекурсивному поведению foldr.
Альтернативно, можно определить foldMap:
instance Foldable Tree where foldMap f Empty = mempty foldMap f (Leaf x) = f x foldMap f (Node l k r) = foldMap f l <> f k <> foldMap f r
И действительно, некоторая эффективность может быть получена путём прямого определения обоих, избегая некоторой косвенности в определениях по умолчанию, которые выражают одно через другое. Если вы реализуете только один, вероятно, foldr — лучший выбор.
Бинарное дерево обычно (при сбалансированности или случайном смещении) обеспечивает одинаково эффективную доступность к левому и правому поддеревьям. Это позволяет определить foldl , оптимизированный для корекурсивных сгибов с операторами, которые ленивы в первом (левом) аргументе.
instance Foldable Tree where foldr f z Empty = z foldr f z (Leaf x) = f x z foldr f z (Node l k r) = foldr f (f k (foldr f z r)) l -- foldMap f Empty = mempty foldMap f (Leaf x) = f x foldMap f (Node l k r) = foldMap f l <> f k <> foldMap f r -- foldl f z Empty = z foldl f z (Leaf x) = f z x foldl f z (Node l k r) = foldl f (f (foldl f z l) k) r
Теперь итерация слева направо и справа налево по элементам структуры одинаково эффективна (обратите внимание на порядок вывода при использовании foldl):
>>> foldr (\e acc -> e : acc) [] (Node (Leaf 1) 2 (Leaf 3)) [1,2,3] >>> foldl (\acc e -> e : acc) [] (Node (Leaf 1) 2 (Leaf 3)) [3,2,1]
Мы можем продолжить это и определить другие методы, отличные от по умолчанию...
Структура определения фактически допускает деревья, неограниченные с одной или обеих сторон. Единственная свертка, которая может правдоподобно завершиться для дерева, неограниченного с обеих сторон, — это null, когда она определена, как показано ниже. Определение по умолчанию в терминах foldr расходится, если дерево неограничено слева. Здесь мы определяем вариант, который избегает прохождения по дереву, чтобы найти самый левый элемент, и просто проверяет корневой узел.
null Empty = True null _ = False
Это разумный выбор и для конечных деревьев.
На практике неограниченные деревья встречаются довольно редко и едва ли можно сказать, что они Foldable. Они обычно используют обход по ширине, и поддерживают только корекурсивные и краткосрочные сгибы (расходятся при строгом сокращении).
Возвращаясь к более простым экземплярам, определённым только в терминах foldr, довольно удивительно, что достаточно эффективная стандартная реализация строгого foldl' определяется через ленивый foldr , когда последний явно предоставляется экземпляром. Может быть полезно взглянуть на то, как это работает.
Быть строгим, будучи ленивым
Иногда полезно, чтобы результатом применения foldr была функция. Это делается путём отображения элементов структуры в функции с одинаковыми типами аргумента и результата. Затем функции по элементам объединяются, чтобы дать конечный результат.
Например, мы можем поменять строгую левую свертку foldl' , написав:
foldl' f z xs = flippedFoldl' f xs z
с функцией flippedFoldl' , определённой ниже, с seq используется для обеспечения строгости в аккумуляторе:
flippedFoldl' f [] z = z flippedFoldl' f (x : xs) z = z `seq` flippedFoldl' f xs (f z x)
Переписав с использованием лямбд, это:
flippedFoldl' f [] = \ b -> b
flippedFoldl' f (x : xs) = \ b -> b `seq` r (f b x)
where r = flippedFoldl' f xs
Вышеприведённое имеет вид правой свертки, что позволяет переписать на:
flippedFoldl' f = \ xs -> foldr f' id xs
where f' x r = \ b -> b `seq` r (f b x)
Теперь мы можем перевернуть это, чтобы получить foldl':
foldl' f z = \ xs -> foldr f' id xs z
-- \ xs -> flippedFoldl' f xs z
where f' x r = \ b -> b `seq` r (f b x)
Функция foldr f' id xs, применённая к z, строится рекурсивно, а её члены применяются к жадно вычисляемому аккумулятору прежде, чем дальнейшие члены применяются к результату. Как требуется, это выполняется в постоянном объёме памяти и может быть оптимизировано до эффективной циклической структуры.
(Фактическое определение foldl' помещает лямбда-выражения в определении f' выше как oneShot, что позволяет произвести дальнейшую оптимизацию).
Законы
Конструктор типов Endo из Data.Monoid связывает с каждым типом b newtype-инкапсулированный тип функций, отображающих b на себя. Функции из типа в себя называются эндоморфизмами, отсюда и название Endo. Тип Endo b является Monoid при композиции функций:
newtype Endo b = Endo { appEndo :: b -> b }
instance Semigroup Endo b where
Endo f <> Endo g = Endo (f . g)
instance Monoid Endo b where
mempty = Endo id
Для каждого Monoid m, у нас также есть Dual моноид Dual m, который объединяет элементы в обратном порядке:
newtype Dual m = Dual { getDual :: m }
instance Semigroup m => Semigroup Dual m where
Dual a <> Dual b = Dual (b <> a)
instance Monoid m => Monoid Dual m where
mempty = Dual mempty
С учётом вышеизложенного, ожидается, что экземпляры Foldable будут удовлетворять следующим законам:
Метод foldr должен быть эквивалентен по значению и строгости замене каждого элемента a структуры Foldable на Endo (f a), композиции их посредством foldMap и применению результата к базовому случаю z:
foldr f z t = appEndo (foldMap (Endo . f) t ) z
Аналогично, метод foldl должен быть эквивалентен по значению и строгости композиции функций flip f a в обратном порядке и применению результата к базовому случаю:
foldl f z t = appEndo (getDual (foldMap (Dual . Endo . flip f) t)) z
Когда элементы структуры берутся из Monoid, определение fold должно совпадать с foldMap id:
fold = foldMap id
Метод length должен совпадать с foldMap отображением каждого элемента на Sum 1 (Тип Sum абстрагирует числа как моноид относительно сложения).
length = getSum . foldMap (Sum . const 1)
sum, product, maximum, и minimum должны быть в сущности эквивалентны foldMap формам, например
sum = getSum . foldMap' Sum product = getProduct . foldMap' Product
но обычно более эффективны, когда определяются более непосредственно как:
sum = foldl' (+) 0 product = foldl' (*) 1
Если структура Foldable имеет экземпляр Functor, то для каждой функции f, отображающей элементы в Monoid, она должна удовлетворять:
foldMap f = fold . fmap f
что подразумевает
foldMap f . fmap g = foldMap (f . g)
Примечания
Поскольку Foldable не имеет Functor как суперкласс, можно определять экземпляры Foldable для структур, которые ограничивают типы их элементов. Поэтому, Set может быть Foldable, даже если множества сохраняют свои элементы в порядке возрастания. Это требует сравнимости элементов, что исключает определение экземпляра Functor для Set.
Класс Foldable позволяет использовать привычные выражения из типа List со структурами контейнеров, которые лучше подходят для данной задачи. Это поддерживает использование более подходящих типов данных Foldable, таких как Seq, Set, NonEmpty, и т. д., без необходимости новых выражений (см. [1] о том, когда не следует использовать списки).
Более общие методы класса Foldable теперь экспортируются из Prelude вместо оригинальных методов, специфичных для списков (см. предложение FTP). Варианты, специфичные для списков, пока доступны в GHC.OldList, но этот модуль предназначен только как временная помощь и может быть удалён в будущем.
Неожиданности могут возникнуть из-за экземпляра Foldable для 2-кортежа (a,), который теперь ведёт себя как контейнер с 1 элементом в своём втором слоте. В контекстах, где ожидается конкретный мономорфный тип, и вы хотите иметь возможность полагаться на ошибки типов для управления рефакторингом, может иметь смысл определить и использовать менее полиморфные варианты некоторых методов Foldable.
Ниже приведены два примера, демонстрирующие определение многоразового менее полиморфного sum и одноразовой специализации length:
{-# LANGUAGE TypeApplications #-}
mySum :: Num a => [a] -> a
mySum = sum
type SlowVector a = [a]
slowLength :: SlowVector -> Int
slowLength v = length @[] v
В обоих случаях, если тип данных, к которому применяется функция, изменится на что-то иное, чем список, место вызова больше не будет компилироваться, пока не будут внесены соответствующие изменения.
Обычно линейное время elem
Возможно, стоит отметить, что, поскольку функция elem в классе Foldable несёт только ограничение Eq на тип элемента, поиск наличия или отсутствия элемента в структуре обычно занимает O(n) времени, даже для упорядоченных структур, таких как Set, которые потенциально способны выполнять поиск быстрее. (Функция member модуля Set несёт ограничение Ord, и может выполнять поиск за O(log n) времени).
Требуется альтернатива методу elem Foldable для абстракции потенциально более быстрого, чем линейный, поиска в общих структурах контейнеров. Этого можно достичь, определив дополнительный тип класса (например, HasMember ниже). Экземпляры такого типа класса (которые также являются Foldable) могут использовать линейный поиск elem в качестве крайнего средства, когда более быстрый поиск не поддерживается.
{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}
import qualified Data.Set as Set
class Eq a => HasMember t a where
member :: a -> t a -> Bool
instance Eq a => HasMember [] a where
member = elem
[...]
instance Ord a => HasMember Set.Set a where
member = Set.member
Вышесказанное предполагает, что elem может быть неуместным в классе Foldable . Альтернативные идеи дизайна запрашиваются на трекере багов GHC через задачу #20421.
Обратите внимание, что некоторые оптимизации, специфичные для структуры, конечно, могут быть возможны непосредственно в соответствующем экземпляре Foldable, например, с Set, размер множества известен заранее, без итерации для подсчёта элементов, и его экземпляр length использует это, чтобы вернуть размер напрямую.
См. также
- [1] «Когда следует использовать списки в Haskell (в основном, не следует)», Иоганнес Валдманн, в arxiv.org, Программирование языков (cs.PL), по адресу https://arxiv.org/abs/1808.08329.
- [2] «Суть паттерна итератора», Джереми Гиббонс и Бруно Оливейра, в Mathematically-Structured Functional Programming, 2006, онлайн по адресу http://www.cs.ox.ac.uk/people/jeremy.gibbons/publications/#iterator.
- [3] «Учебное пособие по универсальности и выразительности fold», Грэхем Хаттон, J. Functional Programming 9 (4): 355–372, июль 1999, онлайн по адресу http://www.cs.nott.ac.uk/~pszgmh/fold.pdf.
© The University of Glasgow and others
Licensed under a BSD-style license (see top of the page).
https://downloads.haskell.org/~ghc/9.12.1/docs/libraries/base-4.21.0.0-8e62/Data-Foldable.html