|
| 1 | +module Data.Semigroup.FoldableWithIndex |
| 2 | +( class FoldableWithIndex1 |
| 3 | +, foldMapWithIndex1 |
| 4 | +, foldWithIndex1 |
| 5 | +, foldrWithIndex1 |
| 6 | +, foldlWithIndex1 |
| 7 | +, traverseWithIndex1_ |
| 8 | +, forWithIndex1_ |
| 9 | +, sequenceWithIndex1_ |
| 10 | +-- , foldrWithIndex1Default |
| 11 | +-- , foldlWithIndex1Default |
| 12 | +, foldMapWithIndex1DefaultR |
| 13 | +, foldMapWithIndex1DefaultL |
| 14 | +, intercalateWithIndex |
| 15 | +, intercalateMapWithIndex |
| 16 | +, maximumByWithIndex |
| 17 | +, minimumByWithIndex |
| 18 | +) where |
| 19 | + |
| 20 | +import Prelude |
| 21 | + |
| 22 | +import Data.FoldableWithIndex (class FoldableWithIndex) |
| 23 | +import Data.FunctorWithIndex (class FunctorWithIndex, mapWithIndex) |
| 24 | +import Data.Identity (Identity(..)) |
| 25 | +import Data.Monoid.Dual (Dual(..)) |
| 26 | +import Data.Monoid.Multiplicative (Multiplicative(..)) |
| 27 | +import Data.Semigroup.Foldable (class Foldable1) |
| 28 | +import Data.Semigroup.Foldable.Internal (Act(..), getAct) |
| 29 | +import Data.Tuple (Tuple(..)) |
| 30 | + |
| 31 | +-- | `FoldableWithIndex1` represents non-empty data structures with indices that can be _folded_. |
| 32 | +-- | |
| 33 | +-- | - `foldrWithIndex1` folds a structure from the right with access to indices |
| 34 | +-- | - `foldlWithIndex1` folds a structure from the left with access to indices |
| 35 | +-- | - `foldMapWithIndex1` folds a structure by accumulating values in a `Semigroup` with access to indices |
| 36 | +-- | |
| 37 | +-- | This is the indexed version of `Foldable1`, for structures with at least one element. |
| 38 | +-- | |
| 39 | +-- | Default implementations are provided by the following functions: |
| 40 | +-- | |
| 41 | +-- | - `foldrWithIndex1Default` |
| 42 | +-- | - `foldlWithIndex1Default` |
| 43 | +-- | - `foldMapWithIndex1DefaultR` |
| 44 | +-- | - `foldMapWithIndex1DefaultL` |
| 45 | +-- | |
| 46 | +-- | Note: some combinations of the default implementations are unsafe to |
| 47 | +-- | use together - causing a non-terminating mutually recursive cycle. |
| 48 | +-- | These combinations are documented per function. |
| 49 | +class (FoldableWithIndex i t, Foldable1 t) <= FoldableWithIndex1 i t | t -> i where |
| 50 | + foldrWithIndex1 :: forall a. (i -> a -> a -> a) -> t a -> a |
| 51 | + foldlWithIndex1 :: forall a. (i -> a -> a -> a) -> t a -> a |
| 52 | + foldMapWithIndex1 :: forall a m. Semigroup m => (i -> a -> m) -> t a -> m |
| 53 | + |
| 54 | +-- | A default implementation of `foldrWithIndex1` using `foldMapWithIndex1`. |
| 55 | +-- | |
| 56 | +-- | Note: when defining a `FoldableWithIndex1` instance, this function is unsafe to use |
| 57 | +-- | in combination with `foldMapWithIndex1DefaultR`. |
| 58 | +-- foldrWithIndex1Default :: forall t i a. FoldableWithIndex1 i t => (i -> a -> a -> a) -> t a -> a |
| 59 | +-- foldrWithIndex1Default f = flip runFoldRightWithIndex1 f <<< foldMapWithIndex1 (curry mkFoldRightWithIndex1) |
| 60 | + |
| 61 | +-- | A default implementation of `foldlWithIndex1` using `foldMapWithIndex1`. |
| 62 | +-- | |
| 63 | +-- | Note: when defining a `FoldableWithIndex1` instance, this function is unsafe to use |
| 64 | +-- | in combination with `foldMapWithIndex1DefaultL`. |
| 65 | +-- foldlWithIndex1Default :: forall t i a. FoldableWithIndex1 i t => (i -> a -> a -> a) -> t a -> a |
| 66 | +-- foldlWithIndex1Default f = runFoldRightWithIndex1 <<< alaF Dual foldMapWithIndex1 (curry mkFoldRightWithIndex1) <<< flip <<< f |
| 67 | + |
| 68 | +-- | A default implementation of `foldMapWithIndex1` using `foldrWithIndex1`. |
| 69 | +-- | |
| 70 | +-- | Note: when defining a `FoldableWithIndex1` instance, this function is unsafe to use |
| 71 | +-- | in combination with `foldrWithIndex1Default`. |
| 72 | +foldMapWithIndex1DefaultR :: forall t i m a. FoldableWithIndex1 i t => FunctorWithIndex i t => Semigroup m => (i -> a -> m) -> t a -> m |
| 73 | +foldMapWithIndex1DefaultR f t = foldrWithIndex1 (\_i m1 m2 -> m1 <> m2) (mapWithIndex f t :: t m) |
| 74 | + |
| 75 | +-- | A default implementation of `foldMapWithIndex1` using `foldlWithIndex1`. |
| 76 | +-- | |
| 77 | +-- | Note: when defining a `FoldableWithIndex1` instance, this function is unsafe to use |
| 78 | +-- | in combination with `foldlWithIndex1Default`. |
| 79 | +foldMapWithIndex1DefaultL :: forall t i m a. FoldableWithIndex1 i t => FunctorWithIndex i t => Semigroup m => (i -> a -> m) -> t a -> m |
| 80 | +foldMapWithIndex1DefaultL f t = foldlWithIndex1 (\_i m1 m2 -> m1 <> m2) (mapWithIndex f t) |
| 81 | + |
| 82 | +instance foldableWithIndex1Dual :: FoldableWithIndex1 Unit Dual where |
| 83 | + foldrWithIndex1 _ (Dual x) = x |
| 84 | + foldlWithIndex1 _ (Dual x) = x |
| 85 | + foldMapWithIndex1 f (Dual x) = f unit x |
| 86 | + |
| 87 | +instance foldableWithIndex1Multiplicative :: FoldableWithIndex1 Unit Multiplicative where |
| 88 | + foldrWithIndex1 _ (Multiplicative x) = x |
| 89 | + foldlWithIndex1 _ (Multiplicative x) = x |
| 90 | + foldMapWithIndex1 f (Multiplicative x) = f unit x |
| 91 | + |
| 92 | +instance foldableWithIndex1Tuple :: FoldableWithIndex1 Unit (Tuple a) where |
| 93 | + foldMapWithIndex1 f (Tuple _ x) = f unit x |
| 94 | + foldrWithIndex1 _ (Tuple _ x) = x |
| 95 | + foldlWithIndex1 _ (Tuple _ x) = x |
| 96 | + |
| 97 | +instance foldableWithIndex1Identity :: FoldableWithIndex1 Unit Identity where |
| 98 | + foldMapWithIndex1 f (Identity x) = f unit x |
| 99 | + foldlWithIndex1 _ (Identity x) = x |
| 100 | + foldrWithIndex1 _ (Identity x) = x |
| 101 | + |
| 102 | +-- | Fold a data structure with access to indices, accumulating values in some `Semigroup`. |
| 103 | +foldWithIndex1 :: forall t i m. FoldableWithIndex1 i t => Semigroup m => t m -> m |
| 104 | +foldWithIndex1 = foldMapWithIndex1 (const identity) |
| 105 | + |
| 106 | +-- | Traverse a data structure with access to indices, performing some effects encoded by an |
| 107 | +-- | `Apply` instance at each value, ignoring the final result. |
| 108 | +traverseWithIndex1_ :: forall t i f a b. FoldableWithIndex1 i t => Apply f => (i -> a -> f b) -> t a -> f Unit |
| 109 | +traverseWithIndex1_ f t = unit <$ getAct (foldMapWithIndex1 (\i -> Act <<< f i) t) |
| 110 | + |
| 111 | +-- | A version of `traverseWithIndex1_` with its arguments flipped. |
| 112 | +-- | |
| 113 | +-- | This can be useful when running an action written using do notation |
| 114 | +-- | for every element in a data structure with access to indices: |
| 115 | +forWithIndex1_ :: forall t i f a b. FoldableWithIndex1 i t => Apply f => t a -> (i -> a -> f b) -> f Unit |
| 116 | +forWithIndex1_ = flip traverseWithIndex1_ |
| 117 | + |
| 118 | +-- | Perform all of the effects in some data structure in the order |
| 119 | +-- | given by the `FoldableWithIndex1` instance, ignoring the final result. |
| 120 | +sequenceWithIndex1_ :: forall t i f a. FoldableWithIndex1 i t => Apply f => t (f a) -> f Unit |
| 121 | +sequenceWithIndex1_ = traverseWithIndex1_ (const identity) |
| 122 | + |
| 123 | +-- | Find the maximum element of a structure with access to indices, according to a given comparison |
| 124 | +-- | function. The comparison function receives the indices and elements. |
| 125 | +maximumByWithIndex :: forall f i a. FoldableWithIndex1 i f => (i -> a -> a -> Ordering) -> f a -> a |
| 126 | +maximumByWithIndex cmp = foldlWithIndex1 \i x y -> if cmp i x y == GT then x else y |
| 127 | + |
| 128 | +-- | Find the minimum element of a structure with access to indices, according to a given comparison |
| 129 | +-- | function. The comparison function receives the indices and elements. |
| 130 | +minimumByWithIndex :: forall f i a. FoldableWithIndex1 i f => (i -> a -> a -> Ordering) -> f a -> a |
| 131 | +minimumByWithIndex cmp = foldlWithIndex1 \i x y -> if cmp i x y == LT then x else y |
| 132 | + |
| 133 | +-- | Internal. Used by intercalation functions with indices. |
| 134 | +newtype JoinWithIndex i a = JoinWithIndex (i -> a -> a) |
| 135 | + |
| 136 | +joineeWithIndex :: forall i a. JoinWithIndex i a -> i -> a -> a |
| 137 | +joineeWithIndex (JoinWithIndex x) = x |
| 138 | + |
| 139 | +instance semigroupJoinWithIndex :: Semigroup a => Semigroup (JoinWithIndex i a) where |
| 140 | + append (JoinWithIndex a) (JoinWithIndex b) = JoinWithIndex $ \i j -> a i j <> j <> b i j |
| 141 | + |
| 142 | +-- | Fold a data structure using a `Semigroup` instance with access to indices, |
| 143 | +-- | combining adjacent elements using the specified separator. |
| 144 | +intercalateWithIndex :: forall f i m. FoldableWithIndex1 i f => Semigroup m => m -> f m -> m |
| 145 | +intercalateWithIndex = flip intercalateMapWithIndex (const identity) |
| 146 | + |
| 147 | +-- | Fold a data structure, accumulating values in some `Semigroup` with access to indices, |
| 148 | +-- | combining adjacent elements using the specified separator. |
| 149 | +intercalateMapWithIndex |
| 150 | + :: forall f i m a |
| 151 | + . FoldableWithIndex1 i f |
| 152 | + => Semigroup m |
| 153 | + => m -> (i -> a -> m) -> f a -> m |
| 154 | +intercalateMapWithIndex j f foldable = |
| 155 | + joineeWithIndex (foldMapWithIndex1 (\i -> JoinWithIndex <<< const <<< const <<< f i) foldable) unit j |
| 156 | + |
| 157 | +-- | Internal. Used by foldrWithIndex1Default and foldlWithIndex1Default. |
| 158 | +data FoldRightWithIndex1 i a = FoldRightWithIndex1 (a -> (i -> a -> a -> a) -> a) a |
| 159 | + |
| 160 | +-- instance foldRightWithIndex1Semigroup :: Semigroup (FoldRightWithIndex1 i a) where |
| 161 | +-- append (FoldRightWithIndex1 lf lr) (FoldRightWithIndex1 rf rr) = FoldRightWithIndex1 (\a f -> lf (f lr (rf a f)) f) rr -- FIXME: An infinite type was inferred for an expression |
| 162 | + |
| 163 | +mkFoldRightWithIndex1 :: forall i a. Tuple i a -> FoldRightWithIndex1 i a |
| 164 | +mkFoldRightWithIndex1 (Tuple _ a) = FoldRightWithIndex1 const a |
| 165 | + |
| 166 | +runFoldRightWithIndex1 :: forall i a. FoldRightWithIndex1 i a -> (i -> a -> a -> a) -> a |
| 167 | +runFoldRightWithIndex1 (FoldRightWithIndex1 f a) = f a |
0 commit comments