Skip to content

Commit a1535be

Browse files
authored
Refactor functors and related packages (#131)
* Refactor functors and related packages This is part of a set of commits that rearrange the dependencies between multiple packages. The immediate motivation is to allow certain newtypes to be reused between `profunctor` and `bifunctors`, but this particular approach goes a little beyond that in two ways: first, it attempts to move data types (`either`, `tuple`) toward the bottom of the dependency stack; and second, it tries to ensure no package comes between `functors` and the packages most closely related to it, in order to open the possibility of merging those packages together (which may be desirable if at some point in the future additional newtypes are added which reveal new and exciting constraints on the module dependency graph). * fixup! Refactor functors and related packages
1 parent 56f238e commit a1535be

File tree

11 files changed

+304
-28
lines changed

11 files changed

+304
-28
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ New features:
1212
- Added `findMapWithIndex` (#119)
1313
- Added `foldr1`, `foldl1`, `foldr1Default`, `foldl1Default`, `foldMap1DefaultR`, `foldMap1DefaultL` (#121, #128)
1414
- Added `maximumBy` and `minimumBy` to `Data.Semigroup.Foldable` (#123)
15+
- Added `lookup` to `Data.Foldable`; this function previously lived in `Data.Tuple` in the `purescript-tuples` package (#131)
1516

1617
Bugfixes:
1718

@@ -21,6 +22,7 @@ Other improvements:
2122
- Wrapped `traverseArrayImpl` IIFE in parentheses (#52)
2223
- Added examples for `sequence` and `traverse` (#115)
2324
- Changed `foldM` type signature to more closely match `foldl` (#111)
25+
- This package now depends on the `purescript-const`, `purescript-either`, `purescript-functors`, `purescript-identity`, and `purescript-tuples` packages, and contains instances previously in those packages or the `purescript-bifunctors` or `purescript-profunctor` packages (#131)
2426

2527
## [v4.1.1](https://github.com/purescript/purescript-foldable-traversable/releases/tag/v4.1.1) - 2018-11-23
2628

bower.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,16 @@
1818
],
1919
"dependencies": {
2020
"purescript-bifunctors": "master",
21+
"purescript-const": "master",
2122
"purescript-control": "master",
23+
"purescript-either": "master",
24+
"purescript-functors": "master",
25+
"purescript-identity": "master",
2226
"purescript-maybe": "master",
2327
"purescript-newtype": "master",
2428
"purescript-orders": "master",
25-
"purescript-prelude": "master"
29+
"purescript-prelude": "master",
30+
"purescript-tuples": "master"
2631
},
2732
"devDependencies": {
2833
"purescript-assert": "master",

src/Data/Bifoldable.purs

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,19 @@ module Data.Bifoldable where
33
import Prelude
44

55
import Control.Apply (applySecond)
6+
import Data.Const (Const(..))
7+
import Data.Either (Either(..))
8+
import Data.Foldable (class Foldable, foldr, foldl, foldMap)
9+
import Data.Functor.Clown (Clown(..))
10+
import Data.Functor.Flip (Flip(..))
11+
import Data.Functor.Joker (Joker(..))
12+
import Data.Functor.Product2 (Product2(..))
613
import Data.Monoid.Conj (Conj(..))
714
import Data.Monoid.Disj (Disj(..))
815
import Data.Monoid.Dual (Dual(..))
916
import Data.Monoid.Endo (Endo(..))
1017
import Data.Newtype (unwrap)
11-
import Data.Foldable (class Foldable, foldr, foldl, foldMap)
12-
import Data.Bifunctor.Clown (Clown(..))
13-
import Data.Bifunctor.Joker (Joker(..))
14-
import Data.Bifunctor.Flip (Flip(..))
15-
import Data.Bifunctor.Product (Product(..))
16-
import Data.Bifunctor.Wrap (Wrap(..))
18+
import Data.Tuple (Tuple(..))
1719

1820
-- | `Bifoldable` represents data structures with two type arguments which can be
1921
-- | folded.
@@ -52,15 +54,28 @@ instance bifoldableFlip :: Bifoldable p => Bifoldable (Flip p) where
5254
bifoldl r l u (Flip p) = bifoldl l r u p
5355
bifoldMap r l (Flip p) = bifoldMap l r p
5456

55-
instance bifoldableProduct :: (Bifoldable f, Bifoldable g) => Bifoldable (Product f g) where
57+
instance bifoldableProduct2 :: (Bifoldable f, Bifoldable g) => Bifoldable (Product2 f g) where
5658
bifoldr l r u m = bifoldrDefault l r u m
5759
bifoldl l r u m = bifoldlDefault l r u m
58-
bifoldMap l r (Product f g) = bifoldMap l r f <> bifoldMap l r g
59-
60-
instance bifoldableWrap :: Bifoldable p => Bifoldable (Wrap p) where
61-
bifoldr l r u (Wrap p) = bifoldr l r u p
62-
bifoldl l r u (Wrap p) = bifoldl l r u p
63-
bifoldMap l r (Wrap p) = bifoldMap l r p
60+
bifoldMap l r (Product2 f g) = bifoldMap l r f <> bifoldMap l r g
61+
62+
instance bifoldableEither :: Bifoldable Either where
63+
bifoldr f _ z (Left a) = f a z
64+
bifoldr _ g z (Right b) = g b z
65+
bifoldl f _ z (Left a) = f z a
66+
bifoldl _ g z (Right b) = g z b
67+
bifoldMap f _ (Left a) = f a
68+
bifoldMap _ g (Right b) = g b
69+
70+
instance bifoldableTuple :: Bifoldable Tuple where
71+
bifoldMap f g (Tuple a b) = f a <> g b
72+
bifoldr f g z (Tuple a b) = f a (g b z)
73+
bifoldl f g z (Tuple a b) = g (f z a) b
74+
75+
instance bifoldableConst :: Bifoldable Const where
76+
bifoldr f _ z (Const a) = f a z
77+
bifoldl f _ z (Const a) = f z a
78+
bifoldMap f _ (Const a) = f a
6479

6580
-- | A default implementation of `bifoldr` using `bifoldMap`.
6681
-- |

src/Data/Bitraversable.purs

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,13 @@ import Prelude
1515
import Data.Bifoldable (class Bifoldable, biall, biany, bifold, bifoldMap, bifoldMapDefaultL, bifoldMapDefaultR, bifoldl, bifoldlDefault, bifoldr, bifoldrDefault, bifor_, bisequence_, bitraverse_)
1616
import Data.Traversable (class Traversable, traverse, sequence)
1717
import Data.Bifunctor (class Bifunctor, bimap)
18-
import Data.Bifunctor.Clown (Clown(..))
19-
import Data.Bifunctor.Joker (Joker(..))
20-
import Data.Bifunctor.Flip (Flip(..))
21-
import Data.Bifunctor.Product (Product(..))
22-
import Data.Bifunctor.Wrap (Wrap(..))
18+
import Data.Const (Const(..))
19+
import Data.Either (Either(..))
20+
import Data.Functor.Clown (Clown(..))
21+
import Data.Functor.Flip (Flip(..))
22+
import Data.Functor.Joker (Joker(..))
23+
import Data.Functor.Product2 (Product2(..))
24+
import Data.Tuple (Tuple(..))
2325

2426
-- | `Bitraversable` represents data structures with two type arguments which can be
2527
-- | traversed.
@@ -48,13 +50,23 @@ instance bitraversableFlip :: Bitraversable p => Bitraversable (Flip p) where
4850
bitraverse r l (Flip p) = Flip <$> bitraverse l r p
4951
bisequence (Flip p) = Flip <$> bisequence p
5052

51-
instance bitraversableProduct :: (Bitraversable f, Bitraversable g) => Bitraversable (Product f g) where
52-
bitraverse l r (Product f g) = Product <$> bitraverse l r f <*> bitraverse l r g
53-
bisequence (Product f g) = Product <$> bisequence f <*> bisequence g
53+
instance bitraversableProduct2 :: (Bitraversable f, Bitraversable g) => Bitraversable (Product2 f g) where
54+
bitraverse l r (Product2 f g) = Product2 <$> bitraverse l r f <*> bitraverse l r g
55+
bisequence (Product2 f g) = Product2 <$> bisequence f <*> bisequence g
5456

55-
instance bitraversableWrap :: Bitraversable p => Bitraversable (Wrap p) where
56-
bitraverse l r (Wrap p) = Wrap <$> bitraverse l r p
57-
bisequence (Wrap p) = Wrap <$> bisequence p
57+
instance bitraversableEither :: Bitraversable Either where
58+
bitraverse f _ (Left a) = Left <$> f a
59+
bitraverse _ g (Right b) = Right <$> g b
60+
bisequence (Left a) = Left <$> a
61+
bisequence (Right b) = Right <$> b
62+
63+
instance bitraversableTuple :: Bitraversable Tuple where
64+
bitraverse f g (Tuple a b) = Tuple <$> f a <*> g b
65+
bisequence (Tuple a b) = Tuple <$> a <*> b
66+
67+
instance bitraversableConst :: Bitraversable Const where
68+
bitraverse f _ (Const a) = Const <$> f a
69+
bisequence (Const a) = Const <$> a
5870

5971
ltraverse
6072
:: forall t b c a f

src/Data/Foldable.purs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@ module Data.Foldable
3434
import Prelude
3535

3636
import Control.Plus (class Plus, alt, empty)
37+
import Data.Const (Const)
38+
import Data.Either (Either(..))
39+
import Data.Functor.App (App(..))
40+
import Data.Functor.Compose (Compose(..))
41+
import Data.Functor.Coproduct (Coproduct, coproduct)
42+
import Data.Functor.Product (Product(..))
43+
import Data.Identity (Identity(..))
3744
import Data.Maybe (Maybe(..))
3845
import Data.Maybe.First (First(..))
3946
import Data.Maybe.Last (Last(..))
@@ -44,6 +51,7 @@ import Data.Monoid.Dual (Dual(..))
4451
import Data.Monoid.Endo (Endo(..))
4552
import Data.Monoid.Multiplicative (Multiplicative(..))
4653
import Data.Newtype (alaF, unwrap)
54+
import Data.Tuple (Tuple(..))
4755

4856
-- | `Foldable` represents data structures which can be _folded_.
4957
-- |
@@ -169,6 +177,49 @@ instance foldableMultiplicative :: Foldable Multiplicative where
169177
foldl f z (Multiplicative x) = z `f` x
170178
foldMap f (Multiplicative x) = f x
171179

180+
instance foldableEither :: Foldable (Either a) where
181+
foldr _ z (Left _) = z
182+
foldr f z (Right x) = f x z
183+
foldl _ z (Left _) = z
184+
foldl f z (Right x) = f z x
185+
foldMap f (Left _) = mempty
186+
foldMap f (Right x) = f x
187+
188+
instance foldableTuple :: Foldable (Tuple a) where
189+
foldr f z (Tuple _ x) = f x z
190+
foldl f z (Tuple _ x) = f z x
191+
foldMap f (Tuple _ x) = f x
192+
193+
instance foldableIdentity :: Foldable Identity where
194+
foldr f z (Identity x) = f x z
195+
foldl f z (Identity x) = f z x
196+
foldMap f (Identity x) = f x
197+
198+
instance foldableConst :: Foldable (Const a) where
199+
foldr _ z _ = z
200+
foldl _ z _ = z
201+
foldMap _ _ = mempty
202+
203+
instance foldableProduct :: (Foldable f, Foldable g) => Foldable (Product f g) where
204+
foldr f z (Product (Tuple fa ga)) = foldr f (foldr f z ga) fa
205+
foldl f z (Product (Tuple fa ga)) = foldl f (foldl f z fa) ga
206+
foldMap f (Product (Tuple fa ga)) = foldMap f fa <> foldMap f ga
207+
208+
instance foldableCoproduct :: (Foldable f, Foldable g) => Foldable (Coproduct f g) where
209+
foldr f z = coproduct (foldr f z) (foldr f z)
210+
foldl f z = coproduct (foldl f z) (foldl f z)
211+
foldMap f = coproduct (foldMap f) (foldMap f)
212+
213+
instance foldableCompose :: (Foldable f, Foldable g) => Foldable (Compose f g) where
214+
foldr f i (Compose fga) = foldr (flip (foldr f)) i fga
215+
foldl f i (Compose fga) = foldl (foldl f) i fga
216+
foldMap f (Compose fga) = foldMap (foldMap f) fga
217+
218+
instance foldableApp :: Foldable f => Foldable (App f) where
219+
foldr f i (App x) = foldr f i x
220+
foldl f i (App x) = foldl f i x
221+
foldMap f (App x) = foldMap f x
222+
172223
-- | Fold a data structure, accumulating values in some `Monoid`.
173224
fold :: forall f m. Foldable f => Monoid m => f m -> m
174225
fold = foldMap identity
@@ -413,3 +464,7 @@ null = foldr (\_ _ -> false) true
413464
-- | is no general way to do better.
414465
length :: forall a b f. Foldable f => Semiring b => f a -> b
415466
length = foldl (\c _ -> add one c) zero
467+
468+
-- | Lookup a value in a data structure of `Tuple`s, generalizing association lists.
469+
lookup :: forall a b f. Foldable f => Eq a => a -> f (Tuple a b) -> Maybe b
470+
lookup a = unwrap <<< foldMap \(Tuple a' b) -> First (if a == a' then Just b else Nothing)

src/Data/FoldableWithIndex.purs

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,15 @@ module Data.FoldableWithIndex
1919

2020
import Prelude
2121

22+
import Data.Const (Const)
23+
import Data.Either (Either(..))
2224
import Data.Foldable (class Foldable, foldMap, foldl, foldr)
25+
import Data.Functor.App (App(..))
26+
import Data.Functor.Compose (Compose(..))
27+
import Data.Functor.Coproduct (Coproduct, coproduct)
28+
import Data.Functor.Product (Product(..))
2329
import Data.FunctorWithIndex (mapWithIndex)
30+
import Data.Identity (Identity(..))
2431
import Data.Maybe (Maybe(..))
2532
import Data.Maybe.First (First)
2633
import Data.Maybe.Last (Last)
@@ -31,6 +38,7 @@ import Data.Monoid.Dual (Dual(..))
3138
import Data.Monoid.Endo (Endo(..))
3239
import Data.Monoid.Multiplicative (Multiplicative)
3340
import Data.Newtype (unwrap)
41+
import Data.Tuple (Tuple(..), curry)
3442

3543
-- | A `Foldable` with an additional index.
3644
-- | A `FoldableWithIndex` instance must be compatible with its `Foldable`
@@ -108,8 +116,6 @@ foldMapWithIndexDefaultL
108116
-> m
109117
foldMapWithIndexDefaultL f = foldlWithIndex (\i acc x -> acc <> f i x) mempty
110118

111-
data Tuple a b = Tuple a b
112-
113119
instance foldableWithIndexArray :: FoldableWithIndex Int Array where
114120
foldrWithIndex f z = foldr (\(Tuple i x) y -> f i x y) z <<< mapWithIndex Tuple
115121
foldlWithIndex f z = foldl (\y (Tuple i x) -> f i y x) z <<< mapWithIndex Tuple
@@ -155,6 +161,49 @@ instance foldableWithIndexMultiplicative :: FoldableWithIndex Unit Multiplicativ
155161
foldlWithIndex f = foldl $ f unit
156162
foldMapWithIndex f = foldMap $ f unit
157163

164+
instance foldableWithIndexEither :: FoldableWithIndex Unit (Either a) where
165+
foldrWithIndex _ z (Left _) = z
166+
foldrWithIndex f z (Right x) = f unit x z
167+
foldlWithIndex _ z (Left _) = z
168+
foldlWithIndex f z (Right x) = f unit z x
169+
foldMapWithIndex f (Left _) = mempty
170+
foldMapWithIndex f (Right x) = f unit x
171+
172+
instance foldableWithIndexTuple :: FoldableWithIndex Unit (Tuple a) where
173+
foldrWithIndex f z (Tuple _ x) = f unit x z
174+
foldlWithIndex f z (Tuple _ x) = f unit z x
175+
foldMapWithIndex f (Tuple _ x) = f unit x
176+
177+
instance foldableWithIndexIdentity :: FoldableWithIndex Unit Identity where
178+
foldrWithIndex f z (Identity x) = f unit x z
179+
foldlWithIndex f z (Identity x) = f unit z x
180+
foldMapWithIndex f (Identity x) = f unit x
181+
182+
instance foldableWithIndexConst :: FoldableWithIndex Void (Const a) where
183+
foldrWithIndex _ z _ = z
184+
foldlWithIndex _ z _ = z
185+
foldMapWithIndex _ _ = mempty
186+
187+
instance foldableWithIndexProduct :: (FoldableWithIndex a f, FoldableWithIndex b g) => FoldableWithIndex (Either a b) (Product f g) where
188+
foldrWithIndex f z (Product (Tuple fa ga)) = foldrWithIndex (f <<< Left) (foldrWithIndex (f <<< Right) z ga) fa
189+
foldlWithIndex f z (Product (Tuple fa ga)) = foldlWithIndex (f <<< Right) (foldlWithIndex (f <<< Left) z fa) ga
190+
foldMapWithIndex f (Product (Tuple fa ga)) = foldMapWithIndex (f <<< Left) fa <> foldMapWithIndex (f <<< Right) ga
191+
192+
instance foldableWithIndexCoproduct :: (FoldableWithIndex a f, FoldableWithIndex b g) => FoldableWithIndex (Either a b) (Coproduct f g) where
193+
foldrWithIndex f z = coproduct (foldrWithIndex (f <<< Left) z) (foldrWithIndex (f <<< Right) z)
194+
foldlWithIndex f z = coproduct (foldlWithIndex (f <<< Left) z) (foldlWithIndex (f <<< Right) z)
195+
foldMapWithIndex f = coproduct (foldMapWithIndex (f <<< Left)) (foldMapWithIndex (f <<< Right))
196+
197+
instance foldableWithIndexCompose :: (FoldableWithIndex a f, FoldableWithIndex b g) => FoldableWithIndex (Tuple a b) (Compose f g) where
198+
foldrWithIndex f i (Compose fga) = foldrWithIndex (\a -> flip (foldrWithIndex (curry f a))) i fga
199+
foldlWithIndex f i (Compose fga) = foldlWithIndex (foldlWithIndex <<< curry f) i fga
200+
foldMapWithIndex f (Compose fga) = foldMapWithIndex (foldMapWithIndex <<< curry f) fga
201+
202+
instance foldableWithIndexApp :: FoldableWithIndex a f => FoldableWithIndex a (App f) where
203+
foldrWithIndex f z (App x) = foldrWithIndex f z x
204+
foldlWithIndex f z (App x) = foldlWithIndex f z x
205+
foldMapWithIndex f (App x) = foldMapWithIndex f x
206+
158207

159208
-- | Similar to 'foldlWithIndex', but the result is encapsulated in a monad.
160209
-- |

src/Data/FunctorWithIndex.purs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@ module Data.FunctorWithIndex
44

55
import Prelude
66

7+
import Data.Bifunctor (bimap)
8+
import Data.Const (Const(..))
9+
import Data.Either (Either(..))
10+
import Data.Functor.App (App(..))
11+
import Data.Functor.Compose (Compose(..))
12+
import Data.Functor.Coproduct (Coproduct(..))
13+
import Data.Functor.Product (Product(..))
14+
import Data.Identity (Identity(..))
715
import Data.Maybe (Maybe)
816
import Data.Maybe.First (First)
917
import Data.Maybe.Last (Last)
@@ -12,6 +20,7 @@ import Data.Monoid.Conj (Conj)
1220
import Data.Monoid.Disj (Disj)
1321
import Data.Monoid.Dual (Dual)
1422
import Data.Monoid.Multiplicative (Multiplicative)
23+
import Data.Tuple (Tuple, curry)
1524

1625
-- | A `Functor` with an additional index.
1726
-- | Instances must satisfy a modified form of the `Functor` laws
@@ -55,6 +64,30 @@ instance functorWithIndexDisj :: FunctorWithIndex Unit Disj where
5564
instance functorWithIndexMultiplicative :: FunctorWithIndex Unit Multiplicative where
5665
mapWithIndex f = map $ f unit
5766

67+
instance functorWithIndexEither :: FunctorWithIndex Unit (Either a) where
68+
mapWithIndex f = map $ f unit
69+
70+
instance functorWithIndexTuple :: FunctorWithIndex Unit (Tuple a) where
71+
mapWithIndex f = map $ f unit
72+
73+
instance functorWithIndexIdentity :: FunctorWithIndex Unit Identity where
74+
mapWithIndex f (Identity a) = Identity (f unit a)
75+
76+
instance functorWithIndexConst :: FunctorWithIndex Void (Const a) where
77+
mapWithIndex _ (Const x) = Const x
78+
79+
instance functorWithIndexProduct :: (FunctorWithIndex a f, FunctorWithIndex b g) => FunctorWithIndex (Either a b) (Product f g) where
80+
mapWithIndex f (Product fga) = Product (bimap (mapWithIndex (f <<< Left)) (mapWithIndex (f <<< Right)) fga)
81+
82+
instance functorWithIndexCoproduct :: (FunctorWithIndex a f, FunctorWithIndex b g) => FunctorWithIndex (Either a b) (Coproduct f g) where
83+
mapWithIndex f (Coproduct e) = Coproduct (bimap (mapWithIndex (f <<< Left)) (mapWithIndex (f <<< Right)) e)
84+
85+
instance functorWithIndexCompose :: (FunctorWithIndex a f, FunctorWithIndex b g) => FunctorWithIndex (Tuple a b) (Compose f g) where
86+
mapWithIndex f (Compose fga) = Compose $ mapWithIndex (mapWithIndex <<< curry f) fga
87+
88+
instance functorWithIndexApp :: FunctorWithIndex a f => FunctorWithIndex a (App f) where
89+
mapWithIndex f (App x) = App $ mapWithIndex f x
90+
5891
-- | A default implementation of Functor's `map` in terms of `mapWithIndex`
5992
mapDefault :: forall i f a b. FunctorWithIndex i f => (a -> b) -> f a -> f b
6093
mapDefault f = mapWithIndex (const f)

src/Data/Semigroup/Foldable.purs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,13 @@ module Data.Semigroup.Foldable
2323
import Prelude
2424

2525
import Data.Foldable (class Foldable)
26+
import Data.Identity (Identity(..))
2627
import Data.Monoid.Dual (Dual(..))
2728
import Data.Monoid.Multiplicative (Multiplicative(..))
2829
import Data.Newtype (ala, alaF)
2930
import Data.Ord.Max (Max(..))
3031
import Data.Ord.Min (Min(..))
32+
import Data.Tuple (Tuple(..))
3133
import Prim.TypeError (class Warn, Text)
3234

3335
-- | `Foldable1` represents data structures with a minimum of one element that can be _folded_.
@@ -93,6 +95,16 @@ instance foldableMultiplicative :: Foldable1 Multiplicative where
9395
foldl1 _ (Multiplicative x) = x
9496
foldMap1 f (Multiplicative x) = f x
9597

98+
instance foldableTuple :: Foldable1 (Tuple a) where
99+
foldMap1 f (Tuple _ x) = f x
100+
foldr1 _ (Tuple _ x) = x
101+
foldl1 _ (Tuple _ x) = x
102+
103+
instance foldableIdentity :: Foldable1 Identity where
104+
foldMap1 f (Identity x) = f x
105+
foldl1 _ (Identity x) = x
106+
foldr1 _ (Identity x) = x
107+
96108
-- | Fold a data structure, accumulating values in some `Semigroup`.
97109
fold1 :: forall t m. Foldable1 t => Semigroup m => t m -> m
98110
fold1 = foldMap1 identity

0 commit comments

Comments
 (0)