@@ -3,9 +3,11 @@ module Data.Bifoldable where
33import Prelude
44
55import Control.Apply ((*>))
6- import Data.Monoid (Monoid )
6+ import Data.Monoid (Monoid , mempty )
77import Data.Monoid.Disj (Disj (..), runDisj )
88import Data.Monoid.Conj (Conj (..), runConj )
9+ import Data.Monoid.Endo (Endo (..), runEndo )
10+ import Data.Monoid.Dual (Dual (..), runDual )
911
1012-- | `Bifoldable` represents data structures with two type arguments which can be
1113-- | folded.
@@ -14,11 +16,60 @@ import Data.Monoid.Conj (Conj(..), runConj)
1416-- | argument. Type class instances should choose the appropriate step function based
1517-- | on the type of the element encountered at each point of the fold.
1618-- |
19+ -- | Default implementations are provided by the following functions:
20+ -- |
21+ -- | - `bifoldrDefault`
22+ -- | - `bifoldlDefault`
23+ -- | - `bifoldMapDefaultR`
24+ -- | - `bifoldMapDefaultL`
25+ -- |
26+ -- | Note: some combinations of the default implementations are unsafe to
27+ -- | use together - causing a non-terminating mutually recursive cycle.
28+ -- | These combinations are documented per function.
1729class Bifoldable p where
1830 bifoldr :: forall a b c . (a -> c -> c ) -> (b -> c -> c ) -> c -> p a b -> c
1931 bifoldl :: forall a b c . (c -> a -> c ) -> (c -> b -> c ) -> c -> p a b -> c
2032 bifoldMap :: forall m a b . (Monoid m ) => (a -> m ) -> (b -> m ) -> p a b -> m
2133
34+
35+ -- | A default implementation of `bifoldr` using `bifoldMap`.
36+ -- |
37+ -- | Note: when defining a `Bifoldable` instance, this function is unsafe to
38+ -- | use in combination with `bifoldMapDefaultR`.
39+ bifoldrDefault :: forall p a b c . (Bifoldable p ) =>
40+ (a -> c -> c ) -> (b -> c -> c ) -> c -> p a b -> c
41+ bifoldrDefault f g z p = runEndo (bifoldMap (Endo <<< f)
42+ (Endo <<< g) p) z
43+
44+ -- | A default implementation of `bifoldl` using `bifoldMap`.
45+ -- |
46+ -- | Note: when defining a `Bifoldable` instance, this function is unsafe to
47+ -- | use in combination with `bifoldMapDefaultL`.
48+ bifoldlDefault :: forall p a b c . (Bifoldable p ) =>
49+ (c -> a -> c ) -> (c -> b -> c ) -> c -> p a b -> c
50+ bifoldlDefault f g z p = runEndo (runDual
51+ (bifoldMap (Dual <<< Endo <<< flip f)
52+ (Dual <<< Endo <<< flip g) p)) z
53+
54+ -- | A default implementation of `bifoldMap` using `bifoldr`.
55+ -- |
56+ -- | Note: when defining a `Bifoldable` instance, this function is unsafe to
57+ -- | use in combination with `bifoldrDefault`.
58+ bifoldMapDefaultR :: forall p m a b . (Bifoldable p , Monoid m ) =>
59+ (a -> m ) -> (b -> m ) -> p a b -> m
60+ bifoldMapDefaultR f g p = bifoldr ((<>) <<< f)
61+ ((<>) <<< g) mempty p
62+
63+ -- | A default implementation of `bifoldMap` using `bifoldl`.
64+ -- |
65+ -- | Note: when defining a `Bifoldable` instance, this function is unsafe to
66+ -- | use in combination with `bifoldlDefault`.
67+ bifoldMapDefaultL :: forall p m a b . (Bifoldable p , Monoid m ) =>
68+ (a -> m ) -> (b -> m ) -> p a b -> m
69+ bifoldMapDefaultL f g p = bifoldl (\m a -> m <> f a)
70+ (\m b -> m <> g b) mempty p
71+
72+
2273-- | Fold a data structure, accumulating values in a monoidal type.
2374bifold :: forall t m . (Bifoldable t , Monoid m ) => t m m -> m
2475bifold = bifoldMap id id
0 commit comments