Skip to content

Commit 7f47130

Browse files
committed
Some new folds and traversals.
1 parent c2b605c commit 7f47130

File tree

6 files changed

+263
-21
lines changed

6 files changed

+263
-21
lines changed

docs/Data/Lens/Fold.md

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,127 @@ foldlOf :: forall s t a b r. Fold (Dual (Endo r)) s t a b -> (r -> a -> r) -> r
5252

5353
Left fold over a `Fold`.
5454

55+
#### `allOf`
56+
57+
``` purescript
58+
allOf :: forall s t a b r. (BooleanAlgebra r) => Fold (Conj r) s t a b -> (a -> r) -> s -> r
59+
```
60+
61+
Whether all foci of a `Fold` satisfy a predicate.
62+
63+
#### `anyOf`
64+
65+
``` purescript
66+
anyOf :: forall s t a b r. (BooleanAlgebra r) => Fold (Disj r) s t a b -> (a -> r) -> s -> r
67+
```
68+
69+
Whether any focus of a `Fold` satisfies a predicate.
70+
71+
#### `andOf`
72+
73+
``` purescript
74+
andOf :: forall s t a b. (BooleanAlgebra a) => Fold (Conj a) s t a b -> s -> a
75+
```
76+
77+
The conjunction of all foci of a `Fold`.
78+
79+
#### `orOf`
80+
81+
``` purescript
82+
orOf :: forall s t a b. (BooleanAlgebra a) => Fold (Disj a) s t a b -> s -> a
83+
```
84+
85+
The disjunction of all foci of a `Fold`.
86+
87+
#### `elemOf`
88+
89+
``` purescript
90+
elemOf :: forall s t a b. (Eq a) => Fold (Disj Boolean) s t a b -> a -> s -> Boolean
91+
```
92+
93+
Whether a `Fold` contains a given element.
94+
95+
#### `notElemOf`
96+
97+
``` purescript
98+
notElemOf :: forall s t a b. (Eq a) => Fold (Conj Boolean) s t a b -> a -> s -> Boolean
99+
```
100+
101+
Whether a `Fold` not contains a given element.
102+
103+
#### `sumOf`
104+
105+
``` purescript
106+
sumOf :: forall s t a b. (Semiring a) => Fold (Additive a) s t a b -> s -> a
107+
```
108+
109+
The sum of all foci of a `Fold`.
110+
111+
#### `productOf`
112+
113+
``` purescript
114+
productOf :: forall s t a b. (Semiring a) => Fold (Multiplicative a) s t a b -> s -> a
115+
```
116+
117+
The product of all foci of a `Fold`.
118+
119+
#### `lengthOf`
120+
121+
``` purescript
122+
lengthOf :: forall s t a b. Fold (Additive Int) s t a b -> s -> Int
123+
```
124+
125+
The number of foci of a `Fold`.
126+
127+
#### `firstOf`
128+
129+
``` purescript
130+
firstOf :: forall s t a b. Fold (First a) s t a b -> s -> Maybe a
131+
```
132+
133+
The first focus of a `Fold`, if there is any. Synonym for `preview`.
134+
135+
#### `lastOf`
136+
137+
``` purescript
138+
lastOf :: forall s t a b. Fold (Last a) s t a b -> s -> Maybe a
139+
```
140+
141+
The last focus of a `Fold`, if there is any.
142+
143+
#### `maximumOf`
144+
145+
``` purescript
146+
maximumOf :: forall s t a b. (Ord a) => Fold (Endo (Maybe a)) s t a b -> s -> Maybe a
147+
```
148+
149+
The maximum of all foci of a `Fold`, if there is any.
150+
151+
#### `minimumOf`
152+
153+
``` purescript
154+
minimumOf :: forall s t a b. (Ord a) => Fold (Endo (Maybe a)) s t a b -> s -> Maybe a
155+
```
156+
157+
The minimum of all foci of a `Fold`, if there is any.
158+
159+
#### `findOf`
160+
161+
``` purescript
162+
findOf :: forall s t a b. Fold (Endo (Maybe a)) s t a b -> (a -> Boolean) -> s -> Maybe a
163+
```
164+
165+
Find the first focus of a `Fold` that satisfies a predicate, if there is any.
166+
167+
#### `sequenceOf_`
168+
169+
``` purescript
170+
sequenceOf_ :: forall f s t a b. (Applicative f) => Fold (Endo (f Unit)) s t (f a) b -> s -> f Unit
171+
```
172+
173+
Sequence the foci of a `Fold`, pulling out an `Applicative`, and ignore
174+
the result. If you need the result, see `sequenceOf` for `Traversal`s.
175+
55176
#### `toListOf`
56177

57178
``` purescript

docs/Data/Lens/Internal/Wander.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@ This module defines the `Wander` type class, which is used to define `Traversal`
55
#### `Wander`
66

77
``` purescript
8-
class (Strong p, Choice p) <= Wander p where
9-
wander :: forall t a b. (Traversable t) => p a b -> p (t a) (t b)
8+
class (Strong p) <= Wander p where
9+
wander :: forall f s t a b. (forall f. (Applicative f) => (a -> f b) -> s -> f t) -> p a b -> p s t
1010
```
1111

12+
Class for profunctors that support polymorphic traversals.
13+
1214
##### Instances
1315
``` purescript
1416
instance wanderFunction :: Wander Function

docs/Data/Lens/Traversal.md

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,38 @@
22

33
This module defines functions for working with traversals.
44

5-
#### `traverse`
5+
#### `traversed`
66

77
``` purescript
8-
traverse :: forall t a b. (Traversable t) => Traversal (t a) (t b) a b
8+
traversed :: forall t a b. (Traversable t) => Traversal (t a) (t b) a b
99
```
1010

1111
Create a `Traversal` which traverses the elements of a `Traversable` functor.
1212

1313
#### `traverseOf`
1414

1515
``` purescript
16-
traverseOf :: forall f s t a b. (Applicative f) => Traversal s t a b -> (a -> f b) -> s -> f t
16+
traverseOf :: forall f s t a b. (Applicative f) => Optic (Star f) s t a b -> (a -> f b) -> s -> f t
1717
```
1818

1919
Turn a pure profunctor `Traversal` into a `lens`-like `Traversal`.
2020

21+
#### `sequenceOf`
22+
23+
``` purescript
24+
sequenceOf :: forall f s t a. (Applicative f) => Optic (Star f) s t (f a) a -> s -> f t
25+
```
26+
27+
Sequence the foci of a `Traversal`, pulling out an `Applicative` effect.
28+
If you do not need the result, see `sequenceOf_` for `Fold`s.
29+
30+
#### `failover`
31+
32+
``` purescript
33+
failover :: forall f s t a b. (Alternative f) => Optic (Star (Tuple (Disj Boolean))) s t a b -> (a -> b) -> s -> f t
34+
```
35+
36+
Tries to map over a `Traversal`; returns `empty`, if the traversal did
37+
not have any new focus.
38+
2139

src/Data/Lens/Fold.purs

Lines changed: 77 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,26 @@
22

33
module Data.Lens.Fold
44
( (^?), (^..)
5-
, preview, foldOf, foldMapOf, foldrOf, foldlOf, toListOf, has, hasn't
6-
, replicated, filtered
5+
, preview, foldOf, foldMapOf, foldrOf, foldlOf, toListOf, firstOf, lastOf
6+
, maximumOf, minimumOf, allOf, anyOf, andOf, orOf, elemOf, notElemOf, sumOf
7+
, productOf, lengthOf, findOf, sequenceOf_, has, hasn't, replicated, filtered
78
) where
89

910
import Prelude
1011
import Data.Const
1112
import Data.Maybe
1213
import Data.List
1314
import Data.Either
15+
import Data.Tuple
1416
import Data.Monoid
1517
import Data.Maybe.First
18+
import Data.Maybe.Last
1619
import Data.Monoid.Endo
1720
import Data.Monoid.Conj
1821
import Data.Monoid.Disj
1922
import Data.Monoid.Dual
23+
import Data.Monoid.Additive
24+
import Data.Monoid.Multiplicative
2025
import Data.Functor.Contravariant
2126
import Data.Foldable
2227
import Data.Profunctor
@@ -54,6 +59,69 @@ foldrOf p f r = flip runEndo r <<< foldMapOf p (Endo <<< f)
5459
foldlOf :: forall s t a b r. Fold (Dual (Endo r)) s t a b -> (r -> a -> r) -> r -> s -> r
5560
foldlOf p f r = flip runEndo r <<< runDual <<< foldMapOf p (Dual <<< Endo <<< flip f)
5661

62+
-- | Whether all foci of a `Fold` satisfy a predicate.
63+
allOf :: forall s t a b r. (BooleanAlgebra r) => Fold (Conj r) s t a b -> (a -> r) -> s -> r
64+
allOf p f = runConj <<< foldMapOf p (Conj <<< f)
65+
66+
-- | Whether any focus of a `Fold` satisfies a predicate.
67+
anyOf :: forall s t a b r. (BooleanAlgebra r) => Fold (Disj r) s t a b -> (a -> r) -> s -> r
68+
anyOf p f = runDisj <<< foldMapOf p (Disj <<< f)
69+
70+
-- | The conjunction of all foci of a `Fold`.
71+
andOf :: forall s t a b. (BooleanAlgebra a) => Fold (Conj a) s t a b -> s -> a
72+
andOf p = allOf p id
73+
74+
-- | The disjunction of all foci of a `Fold`.
75+
orOf :: forall s t a b. (BooleanAlgebra a) => Fold (Disj a) s t a b -> s -> a
76+
orOf p = anyOf p id
77+
78+
-- | Whether a `Fold` contains a given element.
79+
elemOf :: forall s t a b. (Eq a) => Fold (Disj Boolean) s t a b -> a -> s -> Boolean
80+
elemOf p a = anyOf p (== a)
81+
82+
-- | Whether a `Fold` not contains a given element.
83+
notElemOf :: forall s t a b. (Eq a) => Fold (Conj Boolean) s t a b -> a -> s -> Boolean
84+
notElemOf p a = allOf p (/= a)
85+
86+
-- | The sum of all foci of a `Fold`.
87+
sumOf :: forall s t a b. (Semiring a) => Fold (Additive a) s t a b -> s -> a
88+
sumOf p = runAdditive <<< foldMapOf p Additive
89+
90+
-- | The product of all foci of a `Fold`.
91+
productOf :: forall s t a b. (Semiring a) => Fold (Multiplicative a) s t a b -> s -> a
92+
productOf p = runMultiplicative <<< foldMapOf p Multiplicative
93+
94+
-- | The number of foci of a `Fold`.
95+
lengthOf :: forall s t a b. Fold (Additive Int) s t a b -> s -> Int
96+
lengthOf p = runAdditive <<< foldMapOf p (const $ Additive 1)
97+
98+
-- | The first focus of a `Fold`, if there is any. Synonym for `preview`.
99+
firstOf :: forall s t a b. Fold (First a) s t a b -> s -> Maybe a
100+
firstOf p = runFirst <<< foldMapOf p (First <<< Just)
101+
102+
-- | The last focus of a `Fold`, if there is any.
103+
lastOf :: forall s t a b. Fold (Last a) s t a b -> s -> Maybe a
104+
lastOf p = runLast <<< foldMapOf p (Last <<< Just)
105+
106+
-- | The maximum of all foci of a `Fold`, if there is any.
107+
maximumOf :: forall s t a b. (Ord a) => Fold (Endo (Maybe a)) s t a b -> s -> Maybe a
108+
maximumOf p = foldrOf p (\a -> Just <<< maybe a (max a)) Nothing where
109+
max a b = if a > b then a else b
110+
111+
-- | The minimum of all foci of a `Fold`, if there is any.
112+
minimumOf :: forall s t a b. (Ord a) => Fold (Endo (Maybe a)) s t a b -> s -> Maybe a
113+
minimumOf p = foldrOf p (\a -> Just <<< maybe a (min a)) Nothing where
114+
min a b = if a > b then a else b
115+
116+
-- | Find the first focus of a `Fold` that satisfies a predicate, if there is any.
117+
findOf :: forall s t a b. Fold (Endo (Maybe a)) s t a b -> (a -> Boolean) -> s -> Maybe a
118+
findOf p f = foldrOf p (\a -> maybe (if f a then Just a else Nothing) Just) Nothing
119+
120+
-- | Sequence the foci of a `Fold`, pulling out an `Applicative`, and ignore
121+
-- | the result. If you need the result, see `sequenceOf` for `Traversal`s.
122+
sequenceOf_ :: forall f s t a b. (Applicative f) => Fold (Endo (f Unit)) s t (f a) b -> s -> f Unit
123+
sequenceOf_ p = flip runEndo (pure unit) <<< foldMapOf p \f -> Endo (f *>)
124+
57125
-- | Collects the foci of a `Fold` into a list.
58126
toListOf :: forall s t a b. Fold (Endo (List a)) s t a b -> s -> List a
59127
toListOf p = foldrOf p (:) Nil
@@ -87,3 +155,10 @@ folded
87155
:: forall f g a b t r. (Applicative f, Contravariant f, Foldable g)
88156
=> Optic (Star f) (g a) b a t
89157
folded p = Star $ foldr (\a r -> runStar p a *> r) (coerce $ pure unit)
158+
159+
-- | Builds a `Fold` using an unfold.
160+
unfolded
161+
:: forall f s t a b. (Applicative f, Contravariant f)
162+
=> (s -> Maybe (Tuple a s)) -> Optic (Star f) s t a b
163+
unfolded f p = Star go where
164+
go = maybe (coerce $ pure unit) (\(Tuple a s) -> runStar p a *> go s) <<< f

src/Data/Lens/Internal/Wander.purs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
11
-- | This module defines the `Wander` type class, which is used to define `Traversal`s.
22

33
module Data.Lens.Internal.Wander where
4-
4+
55
import Prelude
66

7-
import Data.Traversable (Traversable, traverse)
87
import Data.Profunctor.Strong (Strong)
9-
import Data.Profunctor.Choice (Choice)
10-
import Data.Profunctor.Star (Star(..))
8+
import Data.Profunctor.Star (Star(..), runStar)
9+
import Data.Identity (Identity (..), runIdentity)
10+
11+
-- | Class for profunctors that support polymorphic traversals.
12+
class (Strong p) <= Wander p where
13+
wander
14+
:: forall f s t a b. (forall f. (Applicative f) => (a -> f b) -> s -> f t)
15+
-> p a b -> p s t
1116

12-
class (Strong p, Choice p) <= Wander p where
13-
wander :: forall t a b. (Traversable t) => p a b -> p (t a) (t b)
14-
1517
instance wanderFunction :: Wander Function where
16-
wander = map
18+
wander t f s = runIdentity $ t (Identity <<< f) s
1719

1820
instance wanderStar :: (Applicative f) => Wander (Star f) where
19-
wander (Star f) = Star (traverse f)
21+
wander t = Star <<< t <<< runStar

src/Data/Lens/Traversal.purs

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,47 @@
11
-- | This module defines functions for working with traversals.
22

33
module Data.Lens.Traversal
4-
( traverse
4+
( traversed
55
, traverseOf
6+
, sequenceOf
7+
, failover
68
) where
79

810
import Prelude
911

1012
import Data.Const
1113
import Data.Monoid
14+
import Data.Monoid.Disj
15+
import Data.Tuple
1216
import Data.Lens.Types
1317
import Data.Profunctor.Star
14-
import Data.Traversable (Traversable)
18+
import Control.Alternative
19+
import Control.Plus
20+
import Data.Traversable (Traversable, traverse)
1521
import Data.Lens.Internal.Wander (wander)
1622

1723
-- | Create a `Traversal` which traverses the elements of a `Traversable` functor.
18-
traverse :: forall t a b. (Traversable t) => Traversal (t a) (t b) a b
19-
traverse = wander
24+
traversed :: forall t a b. (Traversable t) => Traversal (t a) (t b) a b
25+
traversed = wander traverse
2026

2127
-- | Turn a pure profunctor `Traversal` into a `lens`-like `Traversal`.
22-
traverseOf :: forall f s t a b. (Applicative f) => Traversal s t a b -> (a -> f b) -> s -> f t
28+
traverseOf
29+
:: forall f s t a b. (Applicative f)
30+
=> Optic (Star f) s t a b -> (a -> f b) -> s -> f t
2331
traverseOf t f = runStar (t (Star f))
32+
33+
-- | Sequence the foci of a `Traversal`, pulling out an `Applicative` effect.
34+
-- | If you do not need the result, see `sequenceOf_` for `Fold`s.
35+
sequenceOf
36+
:: forall f s t a. (Applicative f)
37+
=> Optic (Star f) s t (f a) a -> s -> f t
38+
sequenceOf t = runStar $ wander id $ t (Star id)
39+
40+
-- | Tries to map over a `Traversal`; returns `empty`, if the traversal did
41+
-- | not have any new focus.
42+
failover
43+
:: forall f s t a b. (Alternative f)
44+
=> Optic (Star (Tuple (Disj Boolean))) s t a b -> (a -> b) -> s -> f t
45+
failover t f s = case runStar (wander id $ t $ Star $ Tuple (Disj true) <<< f) s of
46+
Tuple (Disj true) x -> pure x
47+
Tuple (Disj false) _ -> empty

0 commit comments

Comments
 (0)