Skip to content

Commit 6b3e32a

Browse files
committed
Began default impls for Bifoldable & Bitraversable
Done --- * Added implementations - bifoldrDefault - bifoldlDefault - bifoldMapLDefault - bifoldMapRDefault - bitraverseDefault - bisequenceDefault * Added documentation + notes about unsafe combinations * Clean up on previous work (reordering, formatting) To do --- * Add tests!
1 parent f8cb763 commit 6b3e32a

File tree

9 files changed

+179
-34
lines changed

9 files changed

+179
-34
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: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ Default implementations are provided by the following functions:
1919

2020
- `foldrDefault`
2121
- `foldlDefault`
22-
- `foldMapDefaultL`
2322
- `foldMapDefaultR`
23+
- `foldMapDefaultL`
2424

25-
Note: that some combinations of the default implementations are unsafe to
25+
Note: some combinations of the default implementations are unsafe to
2626
use together - causing a non-terminating mutually recursive cycle.
2727
These combinations are documented per function.
2828

@@ -45,7 +45,7 @@ instance foldableMultiplicative :: Foldable Multiplicative
4545
foldrDefault :: forall f a b. (Foldable f) => (a -> b -> b) -> b -> f a -> b
4646
```
4747

48-
A default implementation of `foldr` using `foldMap`
48+
A default implementation of `foldr` using `foldMap`.
4949

5050
Note: when defining a `Foldable` instance, this function is unsafe to use
5151
in combination with `foldMapDefaultR`.
@@ -56,32 +56,32 @@ in combination with `foldMapDefaultR`.
5656
foldlDefault :: forall f a b. (Foldable f) => (b -> a -> b) -> b -> f a -> b
5757
```
5858

59-
A default implementation of `foldl` using `foldMap`
59+
A default implementation of `foldl` using `foldMap`.
6060

6161
Note: when defining a `Foldable` instance, this function is unsafe to use
6262
in combination with `foldMapDefaultL`.
6363

64-
#### `foldMapDefaultL`
64+
#### `foldMapDefaultR`
6565

6666
``` purescript
67-
foldMapDefaultL :: forall f a m. (Foldable f, Monoid m) => (a -> m) -> f a -> m
67+
foldMapDefaultR :: forall f a m. (Foldable f, Monoid m) => (a -> m) -> f a -> m
6868
```
6969

70-
A default implementation of `foldMap` using `foldl`
70+
A default implementation of `foldMap` using `foldr`.
7171

7272
Note: when defining a `Foldable` instance, this function is unsafe to use
73-
in combination with `foldlDefault`.
73+
in combination with `foldrDefault`.
7474

75-
#### `foldMapDefaultR`
75+
#### `foldMapDefaultL`
7676

7777
``` purescript
78-
foldMapDefaultR :: forall f a m. (Foldable f, Monoid m) => (a -> m) -> f a -> m
78+
foldMapDefaultL :: forall f a m. (Foldable f, Monoid m) => (a -> m) -> f a -> m
7979
```
8080

81-
A default implementation of `foldMap` using `foldr`
81+
A default implementation of `foldMap` using `foldl`.
8282

8383
Note: when defining a `Foldable` instance, this function is unsafe to use
84-
in combination with `foldrDefault`.
84+
in combination with `foldlDefault`.
8585

8686
#### `fold`
8787

docs/Data/Traversable.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,15 +51,15 @@ instance traversableMultiplicative :: Traversable Multiplicative
5151
traverseDefault :: forall t a b m. (Traversable t, Applicative m) => (a -> m b) -> t a -> m (t b)
5252
```
5353

54-
A default implementation of `traverse` using `sequence` and `map`
54+
A default implementation of `traverse` using `sequence` and `map`.
5555

5656
#### `sequenceDefault`
5757

5858
``` purescript
5959
sequenceDefault :: forall t a m. (Traversable t, Applicative m) => t (m a) -> m (t a)
6060
```
6161

62-
A default implementation of `sequence` using `traverse`
62+
A default implementation of `sequence` using `traverse`.
6363

6464
#### `for`
6565

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: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,10 @@ import Data.Monoid.Multiplicative (Multiplicative(..))
4242
-- |
4343
-- | - `foldrDefault`
4444
-- | - `foldlDefault`
45-
-- | - `foldMapDefaultL`
4645
-- | - `foldMapDefaultR`
46+
-- | - `foldMapDefaultL`
4747
-- |
48-
-- | Note: that some combinations of the default implementations are unsafe to
48+
-- | Note: some combinations of the default implementations are unsafe to
4949
-- | use together - causing a non-terminating mutually recursive cycle.
5050
-- | These combinations are documented per function.
5151
class Foldable f where
@@ -54,37 +54,37 @@ class Foldable f where
5454
foldMap :: forall a m. (Monoid m) => (a -> m) -> f a -> m
5555

5656

57-
-- | A default implementation of `foldr` using `foldMap`
57+
-- | A default implementation of `foldr` using `foldMap`.
5858
-- |
5959
-- | Note: when defining a `Foldable` instance, this function is unsafe to use
6060
-- | in combination with `foldMapDefaultR`.
6161
foldrDefault :: forall f a b. (Foldable f) =>
6262
(a -> b -> b) -> b -> f a -> b
6363
foldrDefault c u xs = runEndo (foldMap (Endo <<< c) xs) u
6464

65-
-- | A default implementation of `foldl` using `foldMap`
65+
-- | A default implementation of `foldl` using `foldMap`.
6666
-- |
6767
-- | Note: when defining a `Foldable` instance, this function is unsafe to use
6868
-- | in combination with `foldMapDefaultL`.
6969
foldlDefault :: forall f a b. (Foldable f) =>
7070
(b -> a -> b) -> b -> f a -> b
7171
foldlDefault c u xs = runEndo (runDual (foldMap (Dual <<< Endo <<< flip c) xs)) u
7272

73-
-- | A default implementation of `foldMap` using `foldl`
73+
-- | A default implementation of `foldMap` using `foldr`.
7474
-- |
7575
-- | Note: when defining a `Foldable` instance, this function is unsafe to use
76-
-- | in combination with `foldlDefault`.
77-
foldMapDefaultL :: forall f a m. (Foldable f, Monoid m) =>
76+
-- | in combination with `foldrDefault`.
77+
foldMapDefaultR :: forall f a m. (Foldable f, Monoid m) =>
7878
(a -> m) -> f a -> m
79-
foldMapDefaultL f xs = foldl (\acc x -> f x <> acc) mempty xs
79+
foldMapDefaultR f xs = foldr (\x acc -> f x <> acc) mempty xs
8080

81-
-- | A default implementation of `foldMap` using `foldr`
81+
-- | A default implementation of `foldMap` using `foldl`.
8282
-- |
8383
-- | Note: when defining a `Foldable` instance, this function is unsafe to use
84-
-- | in combination with `foldrDefault`.
85-
foldMapDefaultR :: forall f a m. (Foldable f, Monoid m) =>
84+
-- | in combination with `foldlDefault`.
85+
foldMapDefaultL :: forall f a m. (Foldable f, Monoid m) =>
8686
(a -> m) -> f a -> m
87-
foldMapDefaultR f xs = foldr (\x acc -> f x <> acc) mempty xs
87+
foldMapDefaultL f xs = foldl (\acc x -> f x <> acc) mempty xs
8888

8989

9090
instance foldableArray :: Foldable Array where

src/Data/Traversable.purs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,14 @@ class (Functor t, Foldable t) <= Traversable t where
4949
sequence :: forall a m. (Applicative m) => t (m a) -> m (t a)
5050

5151

52-
-- | A default implementation of `traverse` using `sequence` and `map`
53-
traverseDefault :: forall t a b m. (Traversable t, Applicative m) => (a -> m b) -> t a -> m (t b)
52+
-- | A default implementation of `traverse` using `sequence` and `map`.
53+
traverseDefault :: forall t a b m. (Traversable t, Applicative m) =>
54+
(a -> m b) -> t a -> m (t b)
5455
traverseDefault f ta = sequence (map f ta)
5556

56-
-- | A default implementation of `sequence` using `traverse`
57-
sequenceDefault :: forall t a m. (Traversable t, Applicative m) => t (m a) -> m (t a)
57+
-- | A default implementation of `sequence` using `traverse`.
58+
sequenceDefault :: forall t a m. (Traversable t, Applicative m) =>
59+
t (m a) -> m (t a)
5860
sequenceDefault tma = traverse id tma
5961

6062

test/Main.purs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ main = do
4646
log "All done!"
4747

4848

49-
testFoldableFWith :: forall f e. (Foldable f, Eq (f Int)) => (Int -> f Int) -> Int -> Eff (assert :: ASSERT | e) Unit
49+
testFoldableFWith :: forall f e. (Foldable f, Eq (f Int)) =>
50+
(Int -> f Int) -> Int -> Eff (assert :: ASSERT | e) Unit
5051
testFoldableFWith f n = do
5152
let arr = f n
5253
let expectedSum = (n / 2) * (n + 1)
@@ -58,7 +59,8 @@ testFoldableFWith f n = do
5859
testFoldableArrayWith = testFoldableFWith arrayFrom1UpTo
5960

6061

61-
testTraversableFWith :: forall f e. (Traversable f, Eq (f Int)) => (Int -> f Int) -> Int -> Eff (assert :: ASSERT | e) Unit
62+
testTraversableFWith :: forall f e. (Traversable f, Eq (f Int)) =>
63+
(Int -> f Int) -> Int -> Eff (assert :: ASSERT | e) Unit
6264
testTraversableFWith f n = do
6365
let arr = f n
6466

0 commit comments

Comments
 (0)