1module Dict (empty,singleton,insert,update
2 ,lookup,findWithDefault
10{-| A dictionary mapping unique keys to values. The keys can be any comparable
11type. This includes `Int`, `Float`, `Time`, `Char`, `String`, and tuples or
12lists of comparable types.
14Insert, remove, and query operations all take *O(log n)* time.
17@docs empty, singleton, insert, update, remove
20@docs member, lookup, findWithDefault
23@docs union, intersect, diff
26@docs keys, values, toList, fromList
29@docs map, foldl, foldr
41-- BBlack and NBlack should only be used during the deletion
42-- algorithm. Any other occurrence is a bug and should fail an assert.
45 -- ^ Double Black, counts as 2 blacks for the invariant
47 -- ^ Negative Black, counts as -1 blacks for the invariant
51showNColor : NColor -> String
52showNColor c = case c of
58data LeafColor = LBlack
59 -- ^ Double Black, counts as 2
62showLColor : LeafColor -> String
63showLColor c = case c of
67data Dict k v = RBNode NColor k v (Dict k v) (Dict k v)
70{-| Create an empty dictionary. -}
71empty : Dict comparable v
74min : Dict k v -> (k,v)
77 RBNode _ k v (RBEmpty LBlack) _ -> (k,v)
78 RBNode _ _ _ l _ -> min l
79 RBEmpty LBlack -> Native.Error.raise "(min Empty) is not defined"
81max : Dict k v -> (k, v)
84 RBNode _ k v _ (RBEmpty _) -> (k,v)
85 RBNode _ _ _ _ r -> max r
86 RBEmpty _ -> Native.Error.raise "(max Empty) is not defined"
88{-| Lookup the value associated with a key. -}
89lookup : comparable -> Dict comparable v -> Maybe v
92 RBEmpty LBlack -> Nothing
94 case Native.Utils.compare k k' of
99{-| Find the value associated with a key. If the key is not found,
100return the default value. -}
101findWithDefault : v -> comparable -> Dict comparable v -> v
102findWithDefault base k t =
104 RBEmpty LBlack -> base
106 case Native.Utils.compare k k' of
107 LT -> findWithDefault base k l
109 GT -> findWithDefault base k r
111{-| Determine if a key is in a dictionary. -}
112member : comparable -> Dict comparable v -> Bool
114member k t = isJust <| lookup k t
116ensureBlackRoot : Dict k v -> Dict k v
119 RBNode Red k v l r -> RBNode Black k v l r
120 RBNode Black _ _ _ _ -> t
123{-| Insert a key-value pair into a dictionary. Replaces value when there is
125insert : comparable -> v -> Dict comparable v -> Dict comparable v
126insert k v t = let u _ = Just v in
129{-| Remove a key-value pair from a dictionary. If the key is not found,
130no changes are made. -}
131remove : comparable -> Dict comparable v -> Dict comparable v
132remove k t = let u _ = Nothing in
135data Flag = Insert | Remove | Same
136showFlag : Flag -> String
137showFlag f = case f of
142{-| Update the value of a dictionary for a specific key with a given function. -}
143update : comparable -> (Maybe v -> Maybe v) -> Dict comparable v -> Dict comparable v
146 RBEmpty LBlack -> case u Nothing of
147 Nothing -> (Same, empty)
148 Just v -> (Insert, RBNode Red k v empty empty)
149 RBNode c k' v l r -> case Native.Utils.compare k k' of
150 EQ -> case u (Just v) of
151 Nothing -> (Remove, rem c l r)
152 Just v' -> (Same, RBNode c k' v' l r)
153 LT -> let (fl, l') = up l in
155 Same -> (Same, RBNode c k' v l' r)
156 Insert -> (Insert, balance c k' v l' r)
157 Remove -> (Remove, bubble c k' v l' r)
158 GT -> let (fl, r') = up r in
160 Same -> (Same, RBNode c k' v l r')
161 Insert -> (Insert, balance c k' v l r')
162 Remove -> (Remove, bubble c k' v l r')
166 Insert -> ensureBlackRoot t'
169{-| Create a dictionary with one key-value pair. -}
170singleton : comparable -> v -> Dict comparable v
171singleton k v = insert k v (RBEmpty LBlack)
173isBBlack : Dict k v -> Bool
174isBBlack t = case t of
175 RBNode BBlack _ _ _ _ -> True
176 RBEmpty LBBlack -> True
179moreBlack : NColor -> NColor
180moreBlack c = case c of
184 BBlack -> Native.Error.raise "Can't make a double black node more black!"
186lessBlack : NColor -> NColor
187lessBlack c = case c of
191 NBlack -> Native.Error.raise "Can't make a negative black node less black!"
193lessBlackTree : Dict k v -> Dict k v
194lessBlackTree t = case t of
195 RBNode c k v l r -> RBNode (lessBlack c) k v l r
196 RBEmpty LBBlack -> RBEmpty LBlack
198reportRemBug : String -> NColor -> String -> String -> a
199reportRemBug msg c lgot rgot =
200 Native.Error.raise . String.concat <| [
201 "Internal red-black tree invariant violated, expected ",
209 "\nPlease report this bug to https://github.com/evancz/Elm/issues"
212-- Remove the top node from the tree, may leave behind BBlacks
213rem : NColor -> Dict k v -> Dict k v -> Dict k v
214rem c l r = case (l, r) of
215 ((RBEmpty _), (RBEmpty _)) -> case c of
216 Red -> RBEmpty LBlack
217 Black -> RBEmpty LBBlack
218 ((RBEmpty cl), (RBNode cr k' v' l' r')) ->
220 (Black, LBlack, Red) -> RBNode Black k' v' l' r'
221 _ -> reportRemBug "Black, LBlack, Red" c (showLColor cl) (showNColor cr)
222 ((RBNode cl k' v' l' r'), (RBEmpty cr)) ->
224 (Black, Red, LBlack) -> RBNode Black k' v' l' r'
225 _ -> reportRemBug "Black, Red, LBlack" c (showNColor cl) (showLColor cr)
226 -- l and r are both RBNodes
227 ((RBNode cl kl vl ll rl), (RBNode cr kr vr lr rr)) ->
228 let l = RBNode cl kl vl ll rl
229 r = RBNode cr kr vr lr rr
231 l' = remove_max cl kl vl ll rl
234-- Kills a BBlack or moves it upward, may leave behind NBlack
235bubble : NColor -> k -> v -> Dict k v -> Dict k v -> Dict k v
236bubble c k v l r = if isBBlack l || isBBlack r
237 then balance (moreBlack c) k v (lessBlackTree l) (lessBlackTree r)
238 else RBNode c k v l r
240-- Removes rightmost node, may leave root as BBlack
241remove_max : NColor -> k -> v -> Dict k v -> Dict k v -> Dict k v
242remove_max c k v l r = case r of
243 RBEmpty _ -> rem c l r
244 RBNode cr kr vr lr rr
245 -> bubble c k v l (remove_max cr kr vr lr rr)
247-- generalized tree balancing act
248balance : NColor -> k -> v -> Dict k v -> Dict k v -> Dict k v
251 balance_node (RBNode c k v l r)
253blackish : Dict k v -> Bool
254blackish t = case t of
255 RBNode c _ _ _ _ -> c == Black || c == BBlack
258balance_node : Dict k v -> Dict k v
260 let assemble col xk xv yk yv zk zv a b c d =
261 RBNode (lessBlack col) yk yv (RBNode Black xk xv a b) (RBNode Black zk zv c d)
265 RBNode col zk zv (RBNode Red yk yv (RBNode Red xk xv a b) c) d ->
266 assemble col xk xv yk yv zk zv a b c d
267 RBNode col zk zv (RBNode Red xk xv a (RBNode Red yk yv b c)) d ->
268 assemble col xk xv yk yv zk zv a b c d
269 RBNode col xk xv a (RBNode Red zk zv (RBNode Red yk yv b c) d) ->
270 assemble col xk xv yk yv zk zv a b c d
271 RBNode col xk xv a (RBNode Red yk yv b (RBNode Red zk zv c d)) ->
272 assemble col xk xv yk yv zk zv a b c d
274 RBNode BBlack xk xv a (RBNode NBlack zk zv (RBNode Black yk yv b c) d) ->
276 (RBNode Black _ _ _ _) ->
277 RBNode Black yk yv (RBNode Black xk xv a b) (balance Black zk zv c (redden d))
280 RBNode BBlack zk zv (RBNode NBlack xk xv a (RBNode Black yk yv b c)) d ->
282 (RBNode Black _ _ _ _) ->
283 RBNode Black yk yv (balance Black xk xv (redden a) b) (RBNode Black zk zv c d)
288-- make the top node black
289blacken : Dict k v -> Dict k v
291 RBEmpty _ -> RBEmpty LBlack
292 RBNode _ k v l r -> RBNode Black k v l r
294-- make the top node red
295redden : Dict k v -> Dict k v
297 RBEmpty _ -> Native.Error.raise "can't make a Leaf red"
298 RBNode _ k v l r -> RBNode Red k v l r
300{-| Apply a function to all values in a dictionary. -}
301map : (a -> b) -> Dict comparable a -> Dict comparable b
304 RBEmpty LBlack -> RBEmpty LBlack
305 RBNode c k v l r -> RBNode c k (f v) (map f l) (map f r)
307{-| Fold over the key-value pairs in a dictionary, in order from lowest
308key to highest key. -}
309foldl : (comparable -> v -> b -> b) -> b -> Dict comparable v -> b
312 RBEmpty LBlack -> acc
313 RBNode _ k v l r -> foldl f (f k v (foldl f acc l)) r
315{-| Fold over the key-value pairs in a dictionary, in order from highest
317foldr : (comparable -> v -> b -> b) -> b -> Dict comparable v -> b
320 RBEmpty LBlack -> acc
321 RBNode _ k v l r -> foldr f (f k v (foldr f acc r)) l
323{-| Combine two dictionaries. If there is a collision, preference is given
324to the first dictionary. -}
325union : Dict comparable v -> Dict comparable v -> Dict comparable v
326union t1 t2 = foldl insert t2 t1
328{-| Keep a key-value pair when its key appears in the second dictionary.
329Preference is given to values in the first dictionary. -}
330intersect : Dict comparable v -> Dict comparable v -> Dict comparable v
332 let combine k v t = if k `member` t2 then insert k v t else t
333 in foldl combine empty t1
335{-| Keep a key-value pair when its key does not appear in the second dictionary.
336Preference is given to the first dictionary. -}
337diff : Dict comparable v -> Dict comparable v -> Dict comparable v
338diff t1 t2 = foldl (\k v t -> remove k t) t1 t2
340{-| Get all of the keys in a dictionary. -}
341keys : Dict comparable v -> [comparable]
342keys t = foldr (\k v acc -> k :: acc) [] t
344{-| Get all of the values in a dictionary. -}
345values : Dict comparable v -> [v]
346values t = foldr (\k v acc -> v :: acc) [] t
348{-| Convert a dictionary into an association list of key-value pairs. -}
349toList : Dict comparable v -> [(comparable,v)]
350toList t = foldr (\k v acc -> (k,v) :: acc) [] t
352{-| Convert an association list into a dictionary. -}
353fromList : [(comparable,v)] -> Dict comparable v
354fromList assocs = List.foldl (\(k,v) d -> insert k v d) empty assocs
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list