-
Notifications
You must be signed in to change notification settings - Fork 24
/
NonEmpty.purs
174 lines (150 loc) · 5.72 KB
/
NonEmpty.purs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
-- | This module defines a generic non-empty data structure, which adds an
-- | additional element to any container type.
module Data.NonEmpty
( NonEmpty(..)
, singleton
, (:|)
, foldl1
, fromNonEmpty
, oneOf
, head
, tail
) where
import Prelude
import Control.Alt ((<|>))
import Control.Alternative (class Alternative)
import Control.Plus (class Plus, empty)
import Data.Eq (class Eq1)
import Data.Foldable (class Foldable, foldl, foldr, foldMap)
import Data.FoldableWithIndex (class FoldableWithIndex, foldMapWithIndex, foldlWithIndex, foldrWithIndex)
import Data.FunctorWithIndex (class FunctorWithIndex, mapWithIndex)
import Data.Maybe (Maybe(..), maybe)
import Data.Ord (class Ord1)
import Data.Semigroup.Foldable (class Foldable1)
import Data.Semigroup.Foldable (foldl1) as Foldable1
import Data.Traversable (class Traversable, traverse, sequence)
import Data.TraversableWithIndex (class TraversableWithIndex, traverseWithIndex)
import Data.Tuple (uncurry)
import Data.Unfoldable (class Unfoldable, unfoldr)
import Data.Unfoldable1 (class Unfoldable1)
-- | A non-empty container of elements of type a.
-- |
-- | ```purescript
-- | import Data.NonEmpty
-- |
-- | nonEmptyArray :: NonEmpty Array Int
-- | nonEmptyArray = NonEmpty 1 [2,3]
-- |
-- | import Data.List(List(..), (:))
-- |
-- | nonEmptyList :: NonEmpty List Int
-- | nonEmptyList = NonEmpty 1 (2 : 3 : Nil)
-- | ```
data NonEmpty f a = NonEmpty a (f a)
-- | An infix synonym for `NonEmpty`.
-- |
-- | ```purescript
-- | nonEmptyArray :: NonEmpty Array Int
-- | nonEmptyArray = 1 :| [2,3]
-- |
-- | nonEmptyList :: NonEmpty List Int
-- | nonEmptyList = 1 :| 2 : 3 : Nil
-- | ```
infixr 5 NonEmpty as :|
-- | Create a non-empty structure with a single value.
-- |
-- | ```purescript
-- | import Prelude
-- |
-- | singleton 1 == 1 :| []
-- | singleton 1 == 1 :| Nil
-- | ```
singleton :: forall f a. Plus f => a -> NonEmpty f a
singleton a = a :| empty
-- | Fold a non-empty structure, collecting results using a binary operation.
-- |
-- | ```purescript
-- | foldl1 (+) (1 :| [2, 3]) == 6
-- | ```
foldl1 :: forall f a. Foldable f => (a -> a -> a) -> NonEmpty f a -> a
foldl1 = Foldable1.foldl1
-- | Apply a function that takes the `first` element and remaining elements
-- | as arguments to a non-empty container.
-- |
-- | For example, return the remaining elements multiplied by the first element:
-- |
-- | ```purescript
-- | fromNonEmpty (\x xs -> map (_ * x) xs) (3 :| [2, 1]) == [6, 3]
-- | ```
fromNonEmpty :: forall f a r. (a -> f a -> r) -> NonEmpty f a -> r
fromNonEmpty f (a :| fa) = a `f` fa
-- | Returns the `alt` (`<|>`) result of:
-- | - The first element lifted to the container of the remaining elements.
-- | - The remaining elements.
-- |
-- | ```purescript
-- | import Data.Maybe(Maybe(..))
-- |
-- | oneOf (1 :| Nothing) == Just 1
-- | oneOf (1 :| Just 2) == Just 1
-- |
-- | oneOf (1 :| [2, 3]) == [1,2,3]
-- | ```
oneOf :: forall f a. Alternative f => NonEmpty f a -> f a
oneOf (a :| fa) = pure a <|> fa
-- | Get the 'first' element of a non-empty container.
-- |
-- | ```purescript
-- | head (1 :| [2, 3]) == 1
-- | ```
head :: forall f a. NonEmpty f a -> a
head (x :| _) = x
-- | Get everything but the 'first' element of a non-empty container.
-- |
-- | ```purescript
-- | tail (1 :| [2, 3]) == [2, 3]
-- | ```
tail :: forall f a. NonEmpty f a -> f a
tail (_ :| xs) = xs
instance showNonEmpty :: (Show a, Show (f a)) => Show (NonEmpty f a) where
show (a :| fa) = "(NonEmpty " <> show a <> " " <> show fa <> ")"
derive instance eqNonEmpty :: (Eq1 f, Eq a) => Eq (NonEmpty f a)
derive instance eq1NonEmpty :: Eq1 f => Eq1 (NonEmpty f)
derive instance ordNonEmpty :: (Ord1 f, Ord a) => Ord (NonEmpty f a)
derive instance ord1NonEmpty :: Ord1 f => Ord1 (NonEmpty f)
derive instance functorNonEmpty :: Functor f => Functor (NonEmpty f)
instance functorWithIndex
:: FunctorWithIndex i f
=> FunctorWithIndex (Maybe i) (NonEmpty f) where
mapWithIndex f (a :| fa) = f Nothing a :| mapWithIndex (f <<< Just) fa
instance foldableNonEmpty :: Foldable f => Foldable (NonEmpty f) where
foldMap f (a :| fa) = f a <> foldMap f fa
foldl f b (a :| fa) = foldl f (f b a) fa
foldr f b (a :| fa) = f a (foldr f b fa)
instance foldableWithIndexNonEmpty
:: (FoldableWithIndex i f)
=> FoldableWithIndex (Maybe i) (NonEmpty f) where
foldMapWithIndex f (a :| fa) = f Nothing a <> foldMapWithIndex (f <<< Just) fa
foldlWithIndex f b (a :| fa) = foldlWithIndex (f <<< Just) (f Nothing b a) fa
foldrWithIndex f b (a :| fa) = f Nothing a (foldrWithIndex (f <<< Just) b fa)
instance traversableNonEmpty :: Traversable f => Traversable (NonEmpty f) where
sequence (a :| fa) = NonEmpty <$> a <*> sequence fa
traverse f (a :| fa) = NonEmpty <$> f a <*> traverse f fa
instance traversableWithIndexNonEmpty
:: (TraversableWithIndex i f)
=> TraversableWithIndex (Maybe i) (NonEmpty f) where
traverseWithIndex f (a :| fa) =
NonEmpty <$> f Nothing a <*> traverseWithIndex (f <<< Just) fa
instance foldable1NonEmpty :: Foldable f => Foldable1 (NonEmpty f) where
foldMap1 f (a :| fa) = foldl (\s a1 -> s <> f a1) (f a) fa
foldr1 f (a :| fa) = maybe a (f a) $ foldr (\a1 -> Just <<< maybe a1 (f a1)) Nothing fa
foldl1 f (a :| fa) = foldl f a fa
instance unfoldable1NonEmpty :: Unfoldable f => Unfoldable1 (NonEmpty f) where
unfoldr1 f b = uncurry (:|) $ unfoldr (map f) <$> f b
-- | This is a lawful `Semigroup` instance that will behave sensibly for common nonempty
-- | containers like lists and arrays. However, it's not guaranteed that `pure` will behave
-- | sensibly alongside `<>` for all types, as we don't have any laws which govern their behavior.
instance semigroupNonEmpty
:: (Applicative f, Semigroup (f a))
=> Semigroup (NonEmpty f a) where
append (a1 :| f1) (a2 :| f2) = a1 :| (f1 <> pure a2 <> f2)