Skip to content

Commit be73dca

Browse files
authored
Merge pull request #121 from rhendric/rhendric/foldl1-and-foldr1
Foldable1.foldr1 and Foldable1.foldl1
2 parents ea905c3 + 5524fee commit be73dca

File tree

3 files changed

+91
-1
lines changed

3 files changed

+91
-1
lines changed

src/Data/Semigroup/Foldable.purs

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,17 @@ module Data.Semigroup.Foldable
22
( class Foldable1
33
, foldMap1
44
, fold1
5+
, foldr1
6+
, foldl1
57
, traverse1_
68
, for1_
79
, sequence1_
810
, foldMap1Default
911
, fold1Default
12+
, fold1DefaultR
13+
, fold1DefaultL
14+
, foldr1Default
15+
, foldl1Default
1016
, intercalate
1117
, intercalateMap
1218
, maximum
@@ -18,42 +24,70 @@ import Prelude
1824
import Data.Foldable (class Foldable)
1925
import Data.Monoid.Dual (Dual(..))
2026
import Data.Monoid.Multiplicative (Multiplicative(..))
21-
import Data.Newtype (ala)
27+
import Data.Newtype (ala, alaF)
2228
import Data.Ord.Max (Max(..))
2329
import Data.Ord.Min (Min(..))
2430

2531
-- | `Foldable1` represents data structures with a minimum of one element that can be _folded_.
2632
-- |
2733
-- | - `fold1` folds a structure using a `Semigroup` instance
2834
-- | - `foldMap1` folds a structure by accumulating values in a `Semigroup`
35+
-- | - `foldr1` folds a structure from the right
36+
-- | - `foldl1` folds a structure from the left
2937
-- |
3038
-- | Default implementations are provided by the following functions:
3139
-- |
3240
-- | - `fold1Default`
41+
-- | - `fold1DefaultR`
42+
-- | - `fold1DefaultL`
3343
-- | - `foldMap1Default`
44+
-- | - `foldr1Default`
45+
-- | - `foldl1Default`
3446
-- |
3547
-- | Note: some combinations of the default implementations are unsafe to
3648
-- | use together - causing a non-terminating mutually recursive cycle.
3749
-- | These combinations are documented per function.
3850
class Foldable t <= Foldable1 t where
3951
foldMap1 :: forall a m. Semigroup m => (a -> m) -> t a -> m
4052
fold1 :: forall m. Semigroup m => t m -> m
53+
foldr1 :: forall a. (a -> a -> a) -> t a -> a
54+
foldl1 :: forall a. (a -> a -> a) -> t a -> a
4155

4256
-- | A default implementation of `fold1` using `foldMap1`.
4357
fold1Default :: forall t m. Foldable1 t => Semigroup m => t m -> m
4458
fold1Default = foldMap1 identity
4559

60+
-- | A default implementation of `fold1` using `foldr1`.
61+
fold1DefaultR :: forall t m. Foldable1 t => Semigroup m => t m -> m
62+
fold1DefaultR = foldr1 append
63+
64+
-- | A default implementation of `fold1` using `foldl1`.
65+
fold1DefaultL :: forall t m. Foldable1 t => Semigroup m => t m -> m
66+
fold1DefaultL = foldl1 append
67+
4668
-- | A default implementation of `foldMap1` using `fold1`.
4769
foldMap1Default :: forall t m a. Foldable1 t => Functor t => Semigroup m => (a -> m) -> t a -> m
4870
foldMap1Default f = (map f) >>> fold1
4971

72+
-- | A default implementation of `foldr1` using `foldMap1`.
73+
foldr1Default :: forall t a. Foldable1 t => (a -> a -> a) -> t a -> a
74+
foldr1Default = flip (runFoldRight1 <<< foldMap1 mkFoldRight1)
75+
76+
-- | A default implementation of `foldl1` using `foldMap1`.
77+
foldl1Default :: forall t a. Foldable1 t => (a -> a -> a) -> t a -> a
78+
foldl1Default = flip (runFoldRight1 <<< alaF Dual foldMap1 mkFoldRight1) <<< flip
79+
5080
instance foldableDual :: Foldable1 Dual where
5181
foldMap1 f (Dual x) = f x
5282
fold1 = fold1Default
83+
foldr1 _ (Dual x) = x
84+
foldl1 _ (Dual x) = x
5385

5486
instance foldableMultiplicative :: Foldable1 Multiplicative where
5587
foldMap1 f (Multiplicative x) = f x
5688
fold1 = fold1Default
89+
foldr1 _ (Multiplicative x) = x
90+
foldl1 _ (Multiplicative x) = x
5791

5892
newtype Act :: forall k. (k -> Type) -> k -> Type
5993
newtype Act f a = Act (f a)
@@ -110,3 +144,15 @@ intercalateMap
110144
=> m -> (a -> m) -> f a -> m
111145
intercalateMap j f foldable =
112146
joinee (foldMap1 (JoinWith <<< const <<< f) foldable) j
147+
148+
-- | Internal. Used by foldr1Default and foldl1Default.
149+
data FoldRight1 a = FoldRight1 (a -> (a -> a -> a) -> a) a
150+
151+
instance foldRight1Semigroup :: Semigroup (FoldRight1 a) where
152+
append (FoldRight1 lf lr) (FoldRight1 rf rr) = FoldRight1 (\a f -> lf (f lr (rf a f)) f) rr
153+
154+
mkFoldRight1 :: forall a. a -> FoldRight1 a
155+
mkFoldRight1 = FoldRight1 const
156+
157+
runFoldRight1 :: forall a. FoldRight1 a -> (a -> a -> a) -> a
158+
runFoldRight1 (FoldRight1 f a) = f a

test/Main.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,24 @@ exports.arrayReplicate = function (n) {
1717
return result;
1818
};
1919
};
20+
21+
exports.mkNEArray = function (nothing) {
22+
return function (just) {
23+
return function (arr) {
24+
return arr.length > 0 ? just(arr) : nothing;
25+
};
26+
};
27+
};
28+
29+
exports.foldMap1NEArray = function (append) {
30+
return function (f) {
31+
return function (arr) {
32+
var acc = f(arr[0]);
33+
var len = arr.length;
34+
for (var i = 1; i < len; i++) {
35+
acc = append(acc)(f(arr[i]));
36+
}
37+
return acc;
38+
};
39+
};
40+
};

test/Main.purs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import Data.Int (toNumber, pow)
1313
import Data.Maybe (Maybe(..))
1414
import Data.Monoid.Additive (Additive(..))
1515
import Data.Newtype (unwrap)
16+
import Data.Semigroup.Foldable (class Foldable1, foldr1, foldl1, fold1Default, foldr1Default, foldl1Default)
1617
import Data.Traversable (class Traversable, sequenceDefault, traverse, sequence, traverseDefault)
1718
import Data.TraversableWithIndex (class TraversableWithIndex, traverseWithIndex)
1819
import Effect (Effect, foreachE)
@@ -24,6 +25,24 @@ import Unsafe.Coerce (unsafeCoerce)
2425
foreign import arrayFrom1UpTo :: Int -> Array Int
2526
foreign import arrayReplicate :: forall a. Int -> a -> Array a
2627

28+
foreign import data NEArray :: Type -> Type
29+
foreign import mkNEArray :: forall r a. r -> (NEArray a -> r) -> Array a -> r
30+
foreign import foldMap1NEArray :: forall r a. (r -> r -> r) -> (a -> r) -> NEArray a -> r
31+
32+
instance foldableNEArray :: Foldable NEArray where
33+
foldMap = foldMap1NEArray append
34+
foldl f = foldlDefault f
35+
foldr f = foldrDefault f
36+
37+
instance foldable1NEArray :: Foldable1 NEArray where
38+
foldMap1 = foldMap1NEArray append
39+
fold1 = fold1Default
40+
foldr1 f = foldr1Default f
41+
foldl1 f = foldl1Default f
42+
43+
maybeMkNEArray :: forall a. Array a -> Maybe (NEArray a)
44+
maybeMkNEArray = mkNEArray Nothing Just
45+
2746
foldableLength :: forall f a. Foldable f => f a -> Int
2847
foldableLength = unwrap <<< foldMap (const (Additive 1))
2948

@@ -177,6 +196,10 @@ main = do
177196
assert $ "*0a*1b*" == surroundMapWithIndex "*" (\i x -> show i <> x) ["a", "b"]
178197
assert $ "*0a*1b*2c*" == surroundMapWithIndex "*" (\i x -> show i <> x) ["a", "b", "c"]
179198

199+
log "Test Foldable1 defaults"
200+
assert $ "(a(b(cd)))" == foldMap (foldr1 (\x y -> "(" <> x <> y <> ")")) (maybeMkNEArray ["a", "b", "c", "d"])
201+
assert $ "(((ab)c)d)" == foldMap (foldl1 (\x y -> "(" <> x <> y <> ")")) (maybeMkNEArray ["a", "b", "c", "d"])
202+
180203
log "All done!"
181204

182205

0 commit comments

Comments
 (0)