Skip to content

Commit 6d7426e

Browse files
committed
Merge pull request #30 from LiamGoodacre/master
Default impls for Foldable & Traversable methods
2 parents f724d28 + b480f9b commit 6d7426e

File tree

9 files changed

+570
-28
lines changed

9 files changed

+570
-28
lines changed

docs/Data/Bifoldable.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,60 @@ A fold for such a structure requires two step functions, one for each type
1616
argument. Type class instances should choose the appropriate step function based
1717
on the type of the element encountered at each point of the fold.
1818

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.
29+
30+
#### `bifoldrDefault`
31+
32+
``` purescript
33+
bifoldrDefault :: forall p a b c. (Bifoldable p) => (a -> c -> c) -> (b -> c -> c) -> c -> p a b -> c
34+
```
35+
36+
A default implementation of `bifoldr` using `bifoldMap`.
37+
38+
Note: when defining a `Bifoldable` instance, this function is unsafe to
39+
use in combination with `bifoldMapDefaultR`.
40+
41+
#### `bifoldlDefault`
42+
43+
``` purescript
44+
bifoldlDefault :: forall p a b c. (Bifoldable p) => (c -> a -> c) -> (c -> b -> c) -> c -> p a b -> c
45+
```
46+
47+
A default implementation of `bifoldl` using `bifoldMap`.
48+
49+
Note: when defining a `Bifoldable` instance, this function is unsafe to
50+
use in combination with `bifoldMapDefaultL`.
51+
52+
#### `bifoldMapDefaultR`
53+
54+
``` purescript
55+
bifoldMapDefaultR :: forall p m a b. (Bifoldable p, Monoid m) => (a -> m) -> (b -> m) -> p a b -> m
56+
```
57+
58+
A default implementation of `bifoldMap` using `bifoldr`.
59+
60+
Note: when defining a `Bifoldable` instance, this function is unsafe to
61+
use in combination with `bifoldrDefault`.
62+
63+
#### `bifoldMapDefaultL`
64+
65+
``` purescript
66+
bifoldMapDefaultL :: forall p m a b. (Bifoldable p, Monoid m) => (a -> m) -> (b -> m) -> p a b -> m
67+
```
68+
69+
A default implementation of `bifoldMap` using `bifoldl`.
70+
71+
Note: when defining a `Bifoldable` instance, this function is unsafe to
72+
use in combination with `bifoldlDefault`.
1973

2074
#### `bifold`
2175

docs/Data/Bitraversable.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,26 @@ A traversal for such a structure requires two functions, one for each type
1515
argument. Type class instances should choose the appropriate function based
1616
on the type of the element encountered at each point of the traversal.
1717

18+
Default implementations are provided by the following functions:
19+
20+
- `bitraverseDefault`
21+
- `bisequenceDefault`
22+
23+
#### `bitraverseDefault`
24+
25+
``` purescript
26+
bitraverseDefault :: forall t f a b c d. (Bitraversable t, Applicative f) => (a -> f c) -> (b -> f d) -> t a b -> f (t c d)
27+
```
28+
29+
A default implementation of `bitraverse` using `bisequence` and `bimap`.
30+
31+
#### `bisequenceDefault`
32+
33+
``` purescript
34+
bisequenceDefault :: forall t f a b. (Bitraversable t, Applicative f) => t (f a) (f b) -> f (t a b)
35+
```
36+
37+
A default implementation of `bisequence` using `bitraverse`.
1838

1939
#### `bifor`
2040

docs/Data/Foldable.md

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,17 @@ class Foldable f where
1515
- `foldl` folds a structure from the left
1616
- `foldMap` folds a structure by accumulating values in a `Monoid`
1717

18+
Default implementations are provided by the following functions:
19+
20+
- `foldrDefault`
21+
- `foldlDefault`
22+
- `foldMapDefaultR`
23+
- `foldMapDefaultL`
24+
25+
Note: some combinations of the default implementations are unsafe to
26+
use together - causing a non-terminating mutually recursive cycle.
27+
These combinations are documented per function.
28+
1829
##### Instances
1930
``` purescript
2031
instance foldableArray :: Foldable Array
@@ -28,6 +39,50 @@ instance foldableConj :: Foldable Conj
2839
instance foldableMultiplicative :: Foldable Multiplicative
2940
```
3041

42+
#### `foldrDefault`
43+
44+
``` purescript
45+
foldrDefault :: forall f a b. (Foldable f) => (a -> b -> b) -> b -> f a -> b
46+
```
47+
48+
A default implementation of `foldr` using `foldMap`.
49+
50+
Note: when defining a `Foldable` instance, this function is unsafe to use
51+
in combination with `foldMapDefaultR`.
52+
53+
#### `foldlDefault`
54+
55+
``` purescript
56+
foldlDefault :: forall f a b. (Foldable f) => (b -> a -> b) -> b -> f a -> b
57+
```
58+
59+
A default implementation of `foldl` using `foldMap`.
60+
61+
Note: when defining a `Foldable` instance, this function is unsafe to use
62+
in combination with `foldMapDefaultL`.
63+
64+
#### `foldMapDefaultR`
65+
66+
``` purescript
67+
foldMapDefaultR :: forall f a m. (Foldable f, Monoid m) => (a -> m) -> f a -> m
68+
```
69+
70+
A default implementation of `foldMap` using `foldr`.
71+
72+
Note: when defining a `Foldable` instance, this function is unsafe to use
73+
in combination with `foldrDefault`.
74+
75+
#### `foldMapDefaultL`
76+
77+
``` purescript
78+
foldMapDefaultL :: forall f a m. (Foldable f, Monoid m) => (a -> m) -> f a -> m
79+
```
80+
81+
A default implementation of `foldMap` using `foldl`.
82+
83+
Note: when defining a `Foldable` instance, this function is unsafe to use
84+
in combination with `foldlDefault`.
85+
3186
#### `fold`
3287

3388
``` purescript

docs/Data/Traversable.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ following sense:
2727

2828
- `foldMap f = runConst <<< traverse (Const <<< f)`
2929

30+
Default implementations are provided by the following functions:
31+
32+
- `traverseDefault`
33+
- `sequenceDefault`
34+
3035
##### Instances
3136
``` purescript
3237
instance traversableArray :: Traversable Array
@@ -40,6 +45,22 @@ instance traversableDisj :: Traversable Disj
4045
instance traversableMultiplicative :: Traversable Multiplicative
4146
```
4247

48+
#### `traverseDefault`
49+
50+
``` purescript
51+
traverseDefault :: forall t a b m. (Traversable t, Applicative m) => (a -> m b) -> t a -> m (t b)
52+
```
53+
54+
A default implementation of `traverse` using `sequence` and `map`.
55+
56+
#### `sequenceDefault`
57+
58+
``` purescript
59+
sequenceDefault :: forall t a m. (Traversable t, Applicative m) => t (m a) -> m (t a)
60+
```
61+
62+
A default implementation of `sequence` using `traverse`.
63+
4364
#### `for`
4465

4566
``` purescript

src/Data/Bifoldable.purs

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ module Data.Bifoldable where
33
import Prelude
44

55
import Control.Apply ((*>))
6-
import Data.Monoid (Monoid)
6+
import Data.Monoid (Monoid, mempty)
77
import Data.Monoid.Disj (Disj(..), runDisj)
88
import 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.
1729
class 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.
2374
bifold :: forall t m. (Bifoldable t, Monoid m) => t m m -> m
2475
bifold = bifoldMap id id

src/Data/Bitraversable.purs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ module Data.Bitraversable where
33
import Prelude
44

55
import Data.Bifoldable
6-
import Data.Bifunctor (Bifunctor)
6+
import Data.Bifunctor (Bifunctor, bimap)
77

88
-- | `Bitraversable` represents data structures with two type arguments which can be
99
-- | traversed.
@@ -12,10 +12,26 @@ import Data.Bifunctor (Bifunctor)
1212
-- | argument. Type class instances should choose the appropriate function based
1313
-- | on the type of the element encountered at each point of the traversal.
1414
-- |
15+
-- | Default implementations are provided by the following functions:
16+
-- |
17+
-- | - `bitraverseDefault`
18+
-- | - `bisequenceDefault`
1519
class (Bifunctor t, Bifoldable t) <= Bitraversable t where
1620
bitraverse :: forall f a b c d. (Applicative f) => (a -> f c) -> (b -> f d) -> t a b -> f (t c d)
1721
bisequence :: forall f a b. (Applicative f) => t (f a) (f b) -> f (t a b)
1822

23+
24+
-- | A default implementation of `bitraverse` using `bisequence` and `bimap`.
25+
bitraverseDefault :: forall t f a b c d. (Bitraversable t, Applicative f) =>
26+
(a -> f c) -> (b -> f d) -> t a b -> f (t c d)
27+
bitraverseDefault f g t = bisequence (bimap f g t)
28+
29+
-- | A default implementation of `bisequence` using `bitraverse`.
30+
bisequenceDefault :: forall t f a b. (Bitraversable t, Applicative f) =>
31+
t (f a) (f b) -> f (t a b)
32+
bisequenceDefault t = bitraverse id id t
33+
34+
1935
-- | Traverse a data structure, accumulating effects and results using an `Applicative` functor.
2036
bifor :: forall t f a b c d. (Bitraversable t, Applicative f) => t a b -> (a -> f c) -> (b -> f d) -> f (t c d)
2137
bifor t f g = bitraverse f g t

src/Data/Foldable.purs

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
module Data.Foldable
22
( Foldable, foldr, foldl, foldMap
3+
, foldrDefault, foldlDefault, foldMapDefaultL, foldMapDefaultR
34
, fold
45
, traverse_
56
, for_
@@ -25,7 +26,8 @@ import Data.Maybe.First (First(..), runFirst)
2526
import Data.Maybe.Last (Last(..))
2627
import Data.Monoid (Monoid, mempty)
2728
import Data.Monoid.Additive (Additive(..))
28-
import Data.Monoid.Dual (Dual(..))
29+
import Data.Monoid.Dual (Dual(..), runDual)
30+
import Data.Monoid.Endo (Endo(..), runEndo)
2931
import Data.Monoid.Disj (Disj(..), runDisj)
3032
import Data.Monoid.Conj (Conj(..), runConj)
3133
import Data.Monoid.Multiplicative (Multiplicative(..))
@@ -35,15 +37,60 @@ import Data.Monoid.Multiplicative (Multiplicative(..))
3537
-- | - `foldr` folds a structure from the right
3638
-- | - `foldl` folds a structure from the left
3739
-- | - `foldMap` folds a structure by accumulating values in a `Monoid`
40+
-- |
41+
-- | Default implementations are provided by the following functions:
42+
-- |
43+
-- | - `foldrDefault`
44+
-- | - `foldlDefault`
45+
-- | - `foldMapDefaultR`
46+
-- | - `foldMapDefaultL`
47+
-- |
48+
-- | Note: some combinations of the default implementations are unsafe to
49+
-- | use together - causing a non-terminating mutually recursive cycle.
50+
-- | These combinations are documented per function.
3851
class Foldable f where
3952
foldr :: forall a b. (a -> b -> b) -> b -> f a -> b
4053
foldl :: forall a b. (b -> a -> b) -> b -> f a -> b
4154
foldMap :: forall a m. (Monoid m) => (a -> m) -> f a -> m
4255

56+
57+
-- | A default implementation of `foldr` using `foldMap`.
58+
-- |
59+
-- | Note: when defining a `Foldable` instance, this function is unsafe to use
60+
-- | in combination with `foldMapDefaultR`.
61+
foldrDefault :: forall f a b. (Foldable f) =>
62+
(a -> b -> b) -> b -> f a -> b
63+
foldrDefault c u xs = runEndo (foldMap (Endo <<< c) xs) u
64+
65+
-- | A default implementation of `foldl` using `foldMap`.
66+
-- |
67+
-- | Note: when defining a `Foldable` instance, this function is unsafe to use
68+
-- | in combination with `foldMapDefaultL`.
69+
foldlDefault :: forall f a b. (Foldable f) =>
70+
(b -> a -> b) -> b -> f a -> b
71+
foldlDefault c u xs = runEndo (runDual (foldMap (Dual <<< Endo <<< flip c) xs)) u
72+
73+
-- | A default implementation of `foldMap` using `foldr`.
74+
-- |
75+
-- | Note: when defining a `Foldable` instance, this function is unsafe to use
76+
-- | in combination with `foldrDefault`.
77+
foldMapDefaultR :: forall f a m. (Foldable f, Monoid m) =>
78+
(a -> m) -> f a -> m
79+
foldMapDefaultR f xs = foldr (\x acc -> f x <> acc) mempty xs
80+
81+
-- | A default implementation of `foldMap` using `foldl`.
82+
-- |
83+
-- | Note: when defining a `Foldable` instance, this function is unsafe to use
84+
-- | in combination with `foldlDefault`.
85+
foldMapDefaultL :: forall f a m. (Foldable f, Monoid m) =>
86+
(a -> m) -> f a -> m
87+
foldMapDefaultL f xs = foldl (\acc x -> f x <> acc) mempty xs
88+
89+
4390
instance foldableArray :: Foldable Array where
44-
foldr = foldrArray
45-
foldl = foldlArray
46-
foldMap f xs = foldr (\x acc -> f x <> acc) mempty xs
91+
foldr = foldrArray
92+
foldl = foldlArray
93+
foldMap = foldMapDefaultR
4794

4895
foreign import foldrArray :: forall a b. (a -> b -> b) -> b -> Array a -> b
4996
foreign import foldlArray :: forall a b. (b -> a -> b) -> b -> Array a -> b

0 commit comments

Comments
 (0)