Skip to content

Commit 363af1e

Browse files
LukaJCBpaf31
authored andcommitted
Add Foldable1 And Traversable1 type classes (#68)
* Add Foldable1 and Traversable1 classes * Add docs * Only export what needs to exported * Remove redundant parens
1 parent 56ce0b3 commit 363af1e

File tree

2 files changed

+124
-0
lines changed

2 files changed

+124
-0
lines changed

src/Data/Semigroup/Foldable.purs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
module Data.Semigroup.Foldable
2+
( class Foldable1
3+
, foldMap1
4+
, fold1
5+
, traverse1_
6+
, for1_
7+
, sequence1_
8+
, foldMap1Default
9+
, fold1Default
10+
) where
11+
12+
import Prelude
13+
import Data.Foldable (class Foldable)
14+
import Data.Monoid.Dual (Dual(..))
15+
import Data.Monoid.Multiplicative (Multiplicative(..))
16+
17+
-- | `Foldable1` represents data structures with a minimum of one element that can be _folded_.
18+
-- |
19+
-- | - `fold1` folds a structure using a `Semigroup` instance
20+
-- | - `foldMap1` folds a structure by accumulating values in a `Semigroup`
21+
-- |
22+
-- | Default implementations are provided by the following functions:
23+
-- |
24+
-- | - `fold1Default`
25+
-- | - `foldMap1Default`
26+
-- |
27+
-- | Note: some combinations of the default implementations are unsafe to
28+
-- | use together - causing a non-terminating mutually recursive cycle.
29+
-- | These combinations are documented per function.
30+
class Foldable t <= Foldable1 t where
31+
foldMap1 :: forall a m. Semigroup m => (a -> m) -> t a -> m
32+
fold1 :: forall m. Semigroup m => t m -> m
33+
34+
-- | A default implementation of `fold1` using `foldMap1`.
35+
fold1Default :: forall t m. Foldable1 t => Semigroup m => t m -> m
36+
fold1Default = foldMap1 id
37+
38+
-- | A default implementation of `foldMap1` using `fold1`.
39+
foldMap1Default :: forall t m a. Foldable1 t => Functor t => Semigroup m => (a -> m) -> t a -> m
40+
foldMap1Default f = (map f) >>> fold1
41+
42+
instance foldableDual :: Foldable1 Dual where
43+
foldMap1 f (Dual x) = f x
44+
fold1 = fold1Default
45+
46+
instance foldableMultiplicative :: Foldable1 Multiplicative where
47+
foldMap1 f (Multiplicative x) = f x
48+
fold1 = fold1Default
49+
50+
newtype Act f a = Act (f a)
51+
52+
getAct :: forall f a. Act f a -> f a
53+
getAct (Act f) = f
54+
55+
instance semigroupAct :: Apply f => Semigroup (Act f a) where
56+
append (Act a) (Act b) = Act (a *> b)
57+
58+
-- | Traverse a data structure, performing some effects encoded by an
59+
-- | `Apply` instance at each value, ignoring the final result.
60+
traverse1_ :: forall t f a b. Foldable1 t => Apply f => (a -> f b) -> t a -> f Unit
61+
traverse1_ f t = unit <$ getAct (foldMap1 (Act <<< f) t)
62+
63+
-- | A version of `traverse1_` with its arguments flipped.
64+
-- |
65+
-- | This can be useful when running an action written using do notation
66+
-- | for every element in a data structure:
67+
for1_ :: forall t f a b. Foldable1 t => Apply f => t a -> (a -> f b) -> f Unit
68+
for1_ = flip traverse1_
69+
70+
-- | Perform all of the effects in some data structure in the order
71+
-- | given by the `Foldable1` instance, ignoring the final result.
72+
sequence1_ :: forall t f a. Foldable1 t => Apply f => t (f a) -> f Unit
73+
sequence1_ = traverse1_ id
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
module Data.Semigroup.Traversable where
2+
3+
import Prelude
4+
import Data.Traversable (class Traversable)
5+
import Data.Semigroup.Foldable (class Foldable1)
6+
7+
-- | `Traversable1` represents data structures with a minimum of one element that can be _traversed_,
8+
-- | accumulating results and effects in some `Applicative` functor.
9+
-- |
10+
-- | - `traverse1` runs an action for every element in a data structure,
11+
-- | and accumulates the results.
12+
-- | - `sequence1` runs the actions _contained_ in a data structure,
13+
-- | and accumulates the results.
14+
-- |
15+
-- | The `traverse1` and `sequence1` functions should be compatible in the
16+
-- | following sense:
17+
-- |
18+
-- | - `traverse1 f xs = sequence1 (f <$> xs)`
19+
-- | - `sequence1 = traverse1 id`
20+
-- |
21+
-- | `Traversable1` instances should also be compatible with the corresponding
22+
-- | `Foldable1` instances, in the following sense:
23+
-- |
24+
-- | - `foldMap1 f = runConst <<< traverse1 (Const <<< f)`
25+
-- |
26+
-- | Default implementations are provided by the following functions:
27+
-- |
28+
-- | - `traverse1Default`
29+
-- | - `sequence1Default`
30+
class (Foldable1 t, Traversable t) <= Traversable1 t where
31+
traverse1 :: forall a b f. Apply f => (a -> f b) -> t a -> f (t b)
32+
sequence1 :: forall b f. Apply f => t (f b) -> f (t b)
33+
34+
-- | A default implementation of `traverse1` using `sequence1`.
35+
traverse1Default
36+
:: forall t a b m
37+
. Traversable1 t
38+
=> Apply m
39+
=> (a -> m b)
40+
-> t a
41+
-> m (t b)
42+
traverse1Default f ta = sequence1 (f <$> ta)
43+
44+
-- | A default implementation of `sequence1` using `traverse1`.
45+
sequence1Default
46+
:: forall t a m
47+
. Traversable1 t
48+
=> Apply m
49+
=> t (m a)
50+
-> m (t a)
51+
sequence1Default = traverse1 id

0 commit comments

Comments
 (0)