Skip to content

Commit 2416261

Browse files
committed
Add NonEmptySet
1 parent 5ecd2e5 commit 2416261

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+
, fromSet
4+
, toSet
5+
, fromFoldable
6+
, fromFoldable1
7+
, toUnfoldable
8+
, toUnfoldable1
9+
, singleton
10+
, map
11+
, member
12+
, insert
13+
, delete
14+
, size
15+
, findMin
16+
, findMax
17+
, unionSet
18+
, unions
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, foldl)
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+
-- | Attempts to create a non-empty set from a possibly-empty set.
45+
fromSet :: forall a. Set a -> Maybe (NonEmptySet a)
46+
fromSet s = if Set.isEmpty s then Nothing else Just (NonEmptySet s)
47+
48+
-- | Forgets the non-empty property of a set, giving a normal possibly-empty
49+
-- | set.
50+
toSet :: forall a. NonEmptySet a -> Set a
51+
toSet (NonEmptySet s) = s
52+
53+
-- | Create a set from a foldable structure.
54+
fromFoldable :: forall f a. Foldable f => Ord a => f a -> Maybe (NonEmptySet a)
55+
fromFoldable = fromSet <<< Set.fromFoldable
56+
57+
-- | Create a set from a non-empty foldable structure.
58+
fromFoldable1 :: forall f a. Foldable1 f => Ord a => f a -> NonEmptySet a
59+
fromFoldable1 = foldMap1 singleton
60+
61+
-- | Convert a set to an unfoldable structure.
62+
toUnfoldable :: forall f a. Unfoldable f => NonEmptySet a -> f a
63+
toUnfoldable (NonEmptySet s) = Set.toUnfoldable s
64+
65+
-- | Convert a set to a non-empty unfoldable structure.
66+
toUnfoldable1 :: forall f a. Unfoldable1 f => NonEmptySet a -> f a
67+
toUnfoldable1 (NonEmptySet s) = unfoldr1 go (Set.toUnfoldable s :: List a)
68+
where
69+
go = unsafePartial case _ of
70+
x : List.Nil -> Tuple x Nothing
71+
x : tail -> Tuple x (Just tail)
72+
73+
derive newtype instance eqNonEmptySet :: Eq a => Eq (NonEmptySet a)
74+
derive newtype instance eq1NonEmptySet :: Eq1 NonEmptySet
75+
derive newtype instance ordNonEmptySet :: Ord a => Ord (NonEmptySet a)
76+
derive newtype instance ord1NonEmptySet :: Ord1 NonEmptySet
77+
derive newtype instance semigroupNonEmptySet :: Ord a => Semigroup (NonEmptySet a)
78+
derive newtype instance foldableNonEmptySet :: Foldable NonEmptySet
79+
80+
instance foldable1NonEmptySet :: Foldable1 NonEmptySet where
81+
foldMap1 f = foldMap1 f <<< toUnfoldable1 :: forall a. NonEmptySet a -> NonEmptyList a
82+
fold1 = foldMap1 identity
83+
84+
instance showNonEmptySet :: Show a => Show (NonEmptySet a) where
85+
show s = "(fromFoldable " <> show (toUnfoldable1 s :: NonEmptyList a) <> ")"
86+
87+
-- | Create a set with one element.
88+
singleton :: forall a. a -> NonEmptySet a
89+
singleton a = NonEmptySet (Set.singleton a)
90+
91+
-- | Maps over the values in a set.
92+
-- |
93+
-- | This operation is not structure-preserving for sets, so is not a valid
94+
-- | `Functor`. An example case: mapping `const x` over a set with `n > 0`
95+
-- | elements will result in a set with one element.
96+
map :: forall a b. Ord b => (a -> b) -> NonEmptySet a -> NonEmptySet b
97+
map f (NonEmptySet s) = NonEmptySet (Set.map f s)
98+
99+
-- | Test if a value is a member of a set.
100+
member :: forall a. Ord a => a -> NonEmptySet a -> Boolean
101+
member a (NonEmptySet m) = Set.member a m
102+
103+
-- | Insert a value into a set.
104+
insert :: forall a. Ord a => a -> NonEmptySet a -> NonEmptySet a
105+
insert a (NonEmptySet s) = NonEmptySet (Set.insert a s)
106+
107+
-- | Delete a value from a non-empty set. If this would empty the set, the
108+
-- | result is `Nothing`.
109+
delete :: forall a. Ord a => a -> NonEmptySet a -> Maybe (NonEmptySet a)
110+
delete a (NonEmptySet s) = fromSet (Set.delete a s)
111+
112+
-- | Find the size of a set.
113+
size :: forall a. NonEmptySet a -> Int
114+
size (NonEmptySet s) = Set.size s
115+
116+
-- | The minimum value in the set.
117+
findMin :: forall a. NonEmptySet a -> a
118+
findMin (NonEmptySet s) = unsafePartial (fromJust (Set.findMin s))
119+
120+
-- | The maximum value in the set.
121+
findMax :: forall a. NonEmptySet a -> a
122+
findMax (NonEmptySet s) = unsafePartial (fromJust (Set.findMax s))
123+
124+
-- | Form the union of a set and the non-empty set.
125+
unionSet :: forall a. Ord a => Set.Set a -> NonEmptySet a -> NonEmptySet a
126+
unionSet s1 (NonEmptySet s2) = NonEmptySet (s1 <> s2)
127+
128+
-- | Form the union of a non-empty collection of non-empty sets.
129+
unions :: forall f a. Foldable1 f => Ord a => f (NonEmptySet a) -> NonEmptySet a
130+
unions = foldl append (NonEmptySet Set.empty)
131+
132+
-- | Form the set difference. `Nothing` if the sets are identical.
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)