mirror of
https://github.com/roc-lang/roc.git
synced 2025-11-01 05:24:15 +00:00
implement Dict/Set completely in roc
This commit is contained in:
parent
d889f1fda9
commit
f9d8e01561
6 changed files with 124 additions and 38 deletions
|
|
@ -1,5 +1,6 @@
|
|||
interface Dict
|
||||
exposes [
|
||||
Dict,
|
||||
empty,
|
||||
single,
|
||||
get,
|
||||
|
|
@ -10,12 +11,11 @@ interface Dict
|
|||
contains,
|
||||
keys,
|
||||
values,
|
||||
union,
|
||||
intersection,
|
||||
difference,
|
||||
insertAll, keepShared, removeAll,
|
||||
]
|
||||
imports [
|
||||
Bool.{ Bool },
|
||||
Result.{ Result },
|
||||
]
|
||||
|
||||
## A [dictionary](https://en.wikipedia.org/wiki/Associative_array) that lets you can associate keys with values.
|
||||
|
|
@ -66,34 +66,95 @@ interface Dict
|
|||
## When comparing two dictionaries for equality, they are `==` only if their both their contents and their
|
||||
## orderings match. This preserves the property that if `dict1 == dict2`, you should be able to rely on
|
||||
## `fn dict1 == fn dict2` also being `True`, even if `fn` relies on the dictionary's ordering.
|
||||
Dict k v := List [Pair k v]
|
||||
|
||||
## An empty dictionary.
|
||||
empty : Dict k v
|
||||
empty = @Dict []
|
||||
|
||||
get : Dict k v, k -> Result v [KeyNotFound]*
|
||||
get = \dict, key ->
|
||||
result = getLowlevel dict key
|
||||
get = \@Dict list, needle ->
|
||||
when List.find list (\Pair key _ -> key == needle) is
|
||||
Ok (Pair _ v) ->
|
||||
Ok v
|
||||
|
||||
when result.flag is
|
||||
True -> Ok result.value
|
||||
False -> Err KeyNotFound
|
||||
|
||||
getLowlevel : Dict k v, k -> { flag : Bool, value : v }
|
||||
Err NotFound ->
|
||||
Err KeyNotFound
|
||||
|
||||
walk : Dict k v, state, (state, k, v -> state) -> state
|
||||
walk = \@Dict list, initialState, transform ->
|
||||
List.walk list initialState (\state, Pair k v -> transform state k v)
|
||||
|
||||
insert : Dict k v, k, v -> Dict k v
|
||||
insert = \@Dict list, k, v ->
|
||||
when List.findIndex list (\Pair key _ -> key == k) is
|
||||
Err NotFound ->
|
||||
insertFresh (@Dict list) k v
|
||||
|
||||
Ok index ->
|
||||
list
|
||||
|> List.set index (Pair k v)
|
||||
|> @Dict
|
||||
|
||||
len : Dict k v -> Nat
|
||||
len = \@Dict list ->
|
||||
List.len list
|
||||
|
||||
remove : Dict k v, k -> Dict k v
|
||||
remove = \@Dict list, key ->
|
||||
when List.findIndex list (\Pair k _ -> k == key) is
|
||||
Err NotFound ->
|
||||
@Dict list
|
||||
|
||||
Ok index ->
|
||||
lastIndex = List.len list - 1
|
||||
|
||||
list
|
||||
|> List.swap index lastIndex
|
||||
|> List.dropLast
|
||||
|> @Dict
|
||||
|
||||
contains : Dict k v, k -> Bool
|
||||
contains = \@Dict list, needle ->
|
||||
when List.find list (\Pair key _val -> key == needle) is
|
||||
Ok _ -> True
|
||||
Err _ -> False
|
||||
|
||||
single : k, v -> Dict k v
|
||||
single = \key, value ->
|
||||
Dict.empty
|
||||
|> Dict.insert key value
|
||||
@Dict [Pair key value]
|
||||
|
||||
## Returns a [List] of the dictionary's keys.
|
||||
keys : Dict k v -> List k
|
||||
keys = \@Dict list ->
|
||||
List.map list (\Pair k _ -> k)
|
||||
|
||||
## Returns a [List] of the dictionary's values.
|
||||
## Returns a [List] of the Dict's values
|
||||
values : Dict k v -> List v
|
||||
union : Dict k v, Dict k v -> Dict k v
|
||||
intersection : Dict k v, Dict k v -> Dict k v
|
||||
difference : Dict k v, Dict k v -> Dict k v
|
||||
values = \@Dict list ->
|
||||
List.map list (\Pair _ v -> v)
|
||||
|
||||
# union : Dict k v, Dict k v -> Dict k v
|
||||
insertAll : Dict k v, Dict k v -> Dict k v
|
||||
insertAll = \xs, @Dict ys ->
|
||||
List.walk ys xs (\state, Pair k v -> Dict.insert state k v)
|
||||
|
||||
# intersection : Dict k v, Dict k v -> Dict k v
|
||||
keepShared : Dict k v, Dict k v -> Dict k v
|
||||
keepShared = \Dict xs, ys ->
|
||||
List.keepIf xs (\Pair k _ -> Dict.contains ys k)
|
||||
|> @Dict
|
||||
|
||||
# difference : Dict k v, Dict k v -> Dict k v
|
||||
removeAll : Dict k v, Dict k v -> Dict k v
|
||||
removeAll = \xs, @Dict ys ->
|
||||
List.walk ys xs (\state, Pair k _ -> Dict.remove state k)
|
||||
|
||||
## Internal helper function to insert a new association
|
||||
##
|
||||
## Precondition: `k` should not exist in the Dict yet.
|
||||
insertFresh : Dict k v, k, v -> Dict k v
|
||||
insertFresh = \@Dict list, k, v ->
|
||||
list
|
||||
|> List.append (Pair k v)
|
||||
|> @Dict
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
interface Set
|
||||
exposes [
|
||||
Set,
|
||||
empty,
|
||||
single,
|
||||
walk,
|
||||
|
|
@ -13,24 +14,41 @@ interface Set
|
|||
intersection,
|
||||
difference,
|
||||
]
|
||||
imports [List, Bool.{ Bool }, Dict.{ values }]
|
||||
imports [List, Bool.{ Bool }, Dict.{ Dict }]
|
||||
|
||||
Set k := Dict.Dict k {}
|
||||
|
||||
fromDict : Dict k {} -> Set k
|
||||
fromDict = \dict -> @Set dict
|
||||
|
||||
toDict : Set k -> Dict k {}
|
||||
toDict = \@Set dict -> dict
|
||||
|
||||
## An empty set.
|
||||
empty : Set k
|
||||
empty = fromDict Dict.empty
|
||||
|
||||
single : k -> Set k
|
||||
single = \key ->
|
||||
Dict.single key {}
|
||||
|
||||
## Make sure never to insert a *NaN* to a [Set]! Because *NaN* is defined to be
|
||||
## unequal to *NaN*, adding a *NaN* results in an entry that can never be
|
||||
## retrieved or removed from the [Set].
|
||||
insert : Set k, k -> Set k
|
||||
insert = \@Set dict, key ->
|
||||
dict
|
||||
|> Dict.insert key {}
|
||||
|> @Set
|
||||
|
||||
len : Set k -> Nat
|
||||
len = \set ->
|
||||
set
|
||||
|> Set.toDict
|
||||
|> Dict.len
|
||||
len = \@Set dict ->
|
||||
Dict.len dict
|
||||
|
||||
## Drops the given element from the set.
|
||||
remove : Set k, k -> Set k
|
||||
remove = \@Set dict, key ->
|
||||
@Set (Dict.remove key dict)
|
||||
|
||||
contains : Set k, k -> Bool
|
||||
contains = \set, key ->
|
||||
|
|
@ -38,15 +56,26 @@ contains = \set, key ->
|
|||
|> Set.toDict
|
||||
|> Dict.contains key
|
||||
|
||||
# toList = \set -> Dict.keys (toDict set)
|
||||
toList : Set k -> List k
|
||||
toList = \@Set dict ->
|
||||
Dict.keys dict
|
||||
|
||||
fromList : List k -> Set k
|
||||
fromList = \list ->
|
||||
initial = (List.withCapacity (List.len list))
|
||||
List.walk list initial \set, key -> Set.insert set key
|
||||
|
||||
union : Set k, Set k -> Set k
|
||||
intersection : Set k, Set k -> Set k
|
||||
difference : Set k, Set k -> Set k
|
||||
union = \@Set dict1, @Set dict2 ->
|
||||
@Set (Dict.insertAll dict1 dict2)
|
||||
|
||||
toDict : Set k -> Dict k {}
|
||||
intersection : Set k, Set k -> Set k
|
||||
intersection = \@Set dict1, @Set dict2 ->
|
||||
@Set (Dict.keepShared dict1 dict2)
|
||||
|
||||
difference : Set k, Set k -> Set k
|
||||
difference = \@Set dict1, @Set dict2 ->
|
||||
@Set (Dict.removeAll dict1 dict2)
|
||||
|
||||
walk : Set k, state, (state, k -> state) -> state
|
||||
walk = \set, state, step ->
|
||||
|
|
|
|||
|
|
@ -328,15 +328,7 @@ pub fn canonicalize_module_defs<'a>(
|
|||
panic!("TODO gracefully handle shadowing in imports.")
|
||||
}
|
||||
}
|
||||
} else if [
|
||||
Symbol::LIST_LIST,
|
||||
Symbol::STR_STR,
|
||||
Symbol::DICT_DICT,
|
||||
Symbol::SET_SET,
|
||||
Symbol::BOX_BOX_TYPE,
|
||||
]
|
||||
.contains(&symbol)
|
||||
{
|
||||
} else if [Symbol::LIST_LIST, Symbol::STR_STR, Symbol::BOX_BOX_TYPE].contains(&symbol) {
|
||||
// These are not aliases but Apply's and we make sure they are always in scope
|
||||
} else {
|
||||
// This is a type alias or ability
|
||||
|
|
|
|||
|
|
@ -4340,13 +4340,16 @@ fn canonicalize_and_constrain<'a>(
|
|||
.into_iter()
|
||||
.map(|(k, v)| (k, (true, v)))
|
||||
.collect();
|
||||
|
||||
for (name, alias) in module_output.scope.aliases {
|
||||
match aliases.entry(name) {
|
||||
Occupied(_) => {
|
||||
// do nothing
|
||||
}
|
||||
Vacant(vacant) => {
|
||||
if !name.is_builtin() || name.module_id() == ModuleId::ENCODE {
|
||||
if name == Symbol::DICT_DICT {
|
||||
vacant.insert((false, alias));
|
||||
} else if !name.is_builtin() || name.module_id() == ModuleId::ENCODE {
|
||||
vacant.insert((false, alias));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1301,7 +1301,7 @@ define_builtins! {
|
|||
9 RESULT_AFTER_ERR: "afterErr"
|
||||
}
|
||||
7 DICT: "Dict" => {
|
||||
0 DICT_DICT: "Dict" imported // the Dict.Dict type alias
|
||||
0 DICT_DICT: "Dict" // the Dict.Dict type alias
|
||||
1 DICT_EMPTY: "empty"
|
||||
2 DICT_SINGLE: "single"
|
||||
3 DICT_GET: "get"
|
||||
|
|
@ -1322,7 +1322,7 @@ define_builtins! {
|
|||
15 DICT_GET_LOWLEVEL: "getLowlevel"
|
||||
}
|
||||
8 SET: "Set" => {
|
||||
0 SET_SET: "Set" imported // the Set.Set type alias
|
||||
0 SET_SET: "Set" // the Set.Set type alias
|
||||
1 SET_EMPTY: "empty"
|
||||
2 SET_SINGLE: "single"
|
||||
3 SET_LEN: "len"
|
||||
|
|
|
|||
|
|
@ -314,7 +314,8 @@ impl Aliases {
|
|||
let (typ, delayed_variables, &mut kind) =
|
||||
match self.aliases.iter_mut().find(|(s, _, _, _)| *s == symbol) {
|
||||
None => internal_error!(
|
||||
"Alias not registered in delayed aliases! {:?}",
|
||||
"Alias {:?} not registered in delayed aliases! {:?}",
|
||||
symbol,
|
||||
&self.aliases
|
||||
),
|
||||
Some((_, typ, delayed_variables, kind)) => (typ, delayed_variables, kind),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue