Skip to content

Commit 8622a23

Browse files
authored
Merge pull request #7 from garyb/nonemptyset
Add `NonEmptySet`
2 parents d8527d8 + 5821310 commit 8622a23

File tree

2 files changed

+150
-1
lines changed

2 files changed

+150
-1
lines changed

bower.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
"purescript-arrays": "^5.0.0",
2020
"purescript-foldable-traversable": "^4.0.0",
2121
"purescript-gen": "^2.0.0",
22-
"purescript-lists": "^5.0.0",
22+
"purescript-lists": "^5.2.0",
2323
"purescript-maybe": "^4.0.0",
2424
"purescript-partial": "^2.0.0",
2525
"purescript-prelude": "^4.0.0",

src/Data/Set/NonEmpty.purs

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
module Data.Set.NonEmpty
2+
( NonEmptySet
3+
, singleton
4+
, cons
5+
, fromSet
6+
, fromFoldable
7+
, fromFoldable1
8+
, toSet
9+
, toUnfoldable
10+
, toUnfoldable1
11+
, map
12+
, member
13+
, insert
14+
, delete
15+
, size
16+
, min
17+
, max
18+
, unionSet
19+
, difference
20+
, subset
21+
, properSubset
22+
, intersection
23+
) where
24+
25+
import Prelude hiding (map)
26+
27+
import Data.Eq (class Eq1)
28+
import Data.Foldable (class Foldable)
29+
import Data.List (List, (:))
30+
import Data.List as List
31+
import Data.List.NonEmpty (NonEmptyList)
32+
import Data.Maybe (Maybe(..), fromJust)
33+
import Data.Ord (class Ord1)
34+
import Data.Semigroup.Foldable (class Foldable1, foldMap1)
35+
import Data.Set (Set)
36+
import Data.Set as Set
37+
import Data.Tuple (Tuple(..))
38+
import Data.Unfoldable (class Unfoldable, class Unfoldable1, unfoldr1)
39+
import Partial.Unsafe (unsafePartial)
40+
41+
-- | `NonEmptySet a` represents a non-empty set of values of type `a`
42+
newtype NonEmptySet a = NonEmptySet (Set a)
43+
44+
derive newtype instance eqNonEmptySet :: Eq a => Eq (NonEmptySet a)
45+
derive newtype instance eq1NonEmptySet :: Eq1 NonEmptySet
46+
derive newtype instance ordNonEmptySet :: Ord a => Ord (NonEmptySet a)
47+
derive newtype instance ord1NonEmptySet :: Ord1 NonEmptySet
48+
derive newtype instance semigroupNonEmptySet :: Ord a => Semigroup (NonEmptySet a)
49+
derive newtype instance foldableNonEmptySet :: Foldable NonEmptySet
50+
51+
instance foldable1NonEmptySet :: Foldable1 NonEmptySet where
52+
foldMap1 f = foldMap1 f <<< toUnfoldable1 :: forall a. NonEmptySet a -> NonEmptyList a
53+
fold1 = foldMap1 identity
54+
55+
instance showNonEmptySet :: Show a => Show (NonEmptySet a) where
56+
show s = "(fromFoldable1 " <> show (toUnfoldable1 s :: NonEmptyList a) <> ")"
57+
58+
-- | Create a set with one element.
59+
singleton :: forall a. a -> NonEmptySet a
60+
singleton a = NonEmptySet (Set.singleton a)
61+
62+
-- | Creates a `NonEmptySet` from an item and a `Set`.
63+
cons :: forall a. Ord a => a -> Set a -> NonEmptySet a
64+
cons a = NonEmptySet <<< Set.insert a
65+
66+
-- | Attempts to create a non-empty set from a possibly-empty set.
67+
fromSet :: forall a. Set a -> Maybe (NonEmptySet a)
68+
fromSet s = if Set.isEmpty s then Nothing else Just (NonEmptySet s)
69+
70+
-- | Create a set from a foldable structure.
71+
fromFoldable :: forall f a. Foldable f => Ord a => f a -> Maybe (NonEmptySet a)
72+
fromFoldable = fromSet <<< Set.fromFoldable
73+
74+
-- | Create a set from a non-empty foldable structure.
75+
fromFoldable1 :: forall f a. Foldable1 f => Ord a => f a -> NonEmptySet a
76+
fromFoldable1 = foldMap1 singleton
77+
78+
-- | Forgets the non-empty property of a set, giving a normal possibly-empty
79+
-- | set.
80+
toSet :: forall a. NonEmptySet a -> Set a
81+
toSet (NonEmptySet s) = s
82+
83+
-- | Convert a set to an unfoldable structure.
84+
toUnfoldable :: forall f a. Unfoldable f => NonEmptySet a -> f a
85+
toUnfoldable (NonEmptySet s) = Set.toUnfoldable s
86+
87+
-- | Convert a set to a non-empty unfoldable structure.
88+
toUnfoldable1 :: forall f a. Unfoldable1 f => NonEmptySet a -> f a
89+
toUnfoldable1 (NonEmptySet s) = unfoldr1 go (Set.toUnfoldable s :: List a)
90+
where
91+
go = unsafePartial case _ of
92+
x : List.Nil -> Tuple x Nothing
93+
x : tail -> Tuple x (Just tail)
94+
95+
-- | Maps over the values in a set.
96+
-- |
97+
-- | This operation is not structure-preserving for sets, so is not a valid
98+
-- | `Functor`. An example case: mapping `const x` over a set with `n > 0`
99+
-- | elements will result in a set with one element.
100+
map :: forall a b. Ord b => (a -> b) -> NonEmptySet a -> NonEmptySet b
101+
map f (NonEmptySet s) = NonEmptySet (Set.map f s)
102+
103+
-- | Test if a value is a member of a set.
104+
member :: forall a. Ord a => a -> NonEmptySet a -> Boolean
105+
member a (NonEmptySet m) = Set.member a m
106+
107+
-- | Insert a value into a set.
108+
insert :: forall a. Ord a => a -> NonEmptySet a -> NonEmptySet a
109+
insert a (NonEmptySet s) = NonEmptySet (Set.insert a s)
110+
111+
-- | Delete a value from a non-empty set. If this would empty the set, the
112+
-- | result is `Nothing`.
113+
delete :: forall a. Ord a => a -> NonEmptySet a -> Maybe (NonEmptySet a)
114+
delete a (NonEmptySet s) = fromSet (Set.delete a s)
115+
116+
-- | Find the size of a set.
117+
size :: forall a. NonEmptySet a -> Int
118+
size (NonEmptySet s) = Set.size s
119+
120+
-- | The minimum value in the set.
121+
min :: forall a. NonEmptySet a -> a
122+
min (NonEmptySet s) = unsafePartial (fromJust (Set.findMin s))
123+
124+
-- | The maximum value in the set.
125+
max :: forall a. NonEmptySet a -> a
126+
max (NonEmptySet s) = unsafePartial (fromJust (Set.findMax s))
127+
128+
-- | Form the union of a set and the non-empty set.
129+
unionSet :: forall a. Ord a => Set.Set a -> NonEmptySet a -> NonEmptySet a
130+
unionSet s1 (NonEmptySet s2) = NonEmptySet (s1 <> s2)
131+
132+
-- | Form the set difference. `Nothing` if the first is a subset of the second.
133+
difference :: forall a. Ord a => NonEmptySet a -> NonEmptySet a -> Maybe (NonEmptySet a)
134+
difference (NonEmptySet s1) (NonEmptySet s2) = fromSet (Set.difference s1 s2)
135+
136+
-- | True if and only if every element in the first set is an element of the
137+
-- | second set.
138+
subset :: forall a. Ord a => NonEmptySet a -> NonEmptySet a -> Boolean
139+
subset (NonEmptySet s1) (NonEmptySet s2) = Set.subset s1 s2
140+
141+
-- | True if and only if the first set is a subset of the second set and the
142+
-- | sets are not equal.
143+
properSubset :: forall a. Ord a => NonEmptySet a -> NonEmptySet a -> Boolean
144+
properSubset (NonEmptySet s1) (NonEmptySet s2) = Set.properSubset s1 s2
145+
146+
-- | The set of elements which are in both the first and second set. `Nothing`
147+
-- | if the sets are disjoint.
148+
intersection :: forall a. Ord a => NonEmptySet a -> NonEmptySet a -> Maybe (NonEmptySet a)
149+
intersection (NonEmptySet s1) (NonEmptySet s2) = fromSet (Set.intersection s1 s2)

0 commit comments

Comments
 (0)