mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 21:39:07 +00:00
Merge pull request #5438 from roc-lang/dict-set-hash-eq
add Hash and Eq to Dict and Set
This commit is contained in:
commit
8ecbd8c071
5 changed files with 171 additions and 47 deletions
|
@ -98,6 +98,30 @@ Dict k v := {
|
|||
data : List (T k v),
|
||||
size : Nat,
|
||||
} | k has Hash & Eq
|
||||
has [
|
||||
Eq {
|
||||
isEq,
|
||||
},
|
||||
Hash {
|
||||
hash: hashDict,
|
||||
},
|
||||
]
|
||||
|
||||
isEq : Dict k v, Dict k v -> Bool | k has Hash & Eq, v has Eq
|
||||
isEq = \xs, ys ->
|
||||
if len xs != len ys then
|
||||
Bool.false
|
||||
else
|
||||
walkUntil xs Bool.true \_, k, xVal ->
|
||||
when get ys k is
|
||||
Ok yVal if yVal == xVal ->
|
||||
Continue Bool.true
|
||||
|
||||
_ ->
|
||||
Break Bool.false
|
||||
|
||||
hashDict : hasher, Dict k v -> hasher | k has Hash & Eq, v has Hash, hasher has Hasher
|
||||
hashDict = \hasher, dict -> Hash.hashUnordered hasher (toList dict) List.walk
|
||||
|
||||
## Return an empty dictionary.
|
||||
## ```
|
||||
|
@ -747,6 +771,71 @@ expect
|
|||
|
||||
val == Ok "bar"
|
||||
|
||||
expect
|
||||
dict1 =
|
||||
empty {}
|
||||
|> insert 1 "bar"
|
||||
|> insert 2 "baz"
|
||||
|
||||
dict2 =
|
||||
empty {}
|
||||
|> insert 2 "baz"
|
||||
|> insert 1 "bar"
|
||||
|
||||
dict1 == dict2
|
||||
|
||||
expect
|
||||
dict1 =
|
||||
empty {}
|
||||
|> insert 1 "bar"
|
||||
|> insert 2 "baz"
|
||||
|
||||
dict2 =
|
||||
empty {}
|
||||
|> insert 1 "bar"
|
||||
|> insert 2 "baz!"
|
||||
|
||||
dict1 != dict2
|
||||
|
||||
expect
|
||||
inner1 =
|
||||
empty {}
|
||||
|> insert 1 "bar"
|
||||
|> insert 2 "baz"
|
||||
|
||||
inner2 =
|
||||
empty {}
|
||||
|> insert 2 "baz"
|
||||
|> insert 1 "bar"
|
||||
|
||||
outer =
|
||||
empty {}
|
||||
|> insert inner1 "wrong"
|
||||
|> insert inner2 "right"
|
||||
|
||||
get outer inner1 == Ok "right"
|
||||
|
||||
expect
|
||||
inner1 =
|
||||
empty {}
|
||||
|> insert 1 "bar"
|
||||
|> insert 2 "baz"
|
||||
|
||||
inner2 =
|
||||
empty {}
|
||||
|> insert 2 "baz"
|
||||
|> insert 1 "bar"
|
||||
|
||||
outer1 =
|
||||
empty {}
|
||||
|> insert inner1 "val"
|
||||
|
||||
outer2 =
|
||||
empty {}
|
||||
|> insert inner2 "val"
|
||||
|
||||
outer1 == outer2
|
||||
|
||||
expect
|
||||
val =
|
||||
empty {}
|
||||
|
|
|
@ -20,19 +20,19 @@ interface Set
|
|||
Bool.{ Bool, Eq },
|
||||
Dict.{ Dict },
|
||||
Num.{ Nat },
|
||||
Hash.{ Hash },
|
||||
Hash.{ Hash, Hasher },
|
||||
]
|
||||
|
||||
# We should have this line above the next has.
|
||||
# It causes the formatter to fail currently.
|
||||
# | k has Hash & Eq
|
||||
## Provides a [set](https://en.wikipedia.org/wiki/Set_(abstract_data_type))
|
||||
## type which stores a collection of unique values, without any ordering
|
||||
Set k := Dict.Dict k {}
|
||||
Set k := Dict.Dict k {} | k has Hash & Eq
|
||||
has [
|
||||
Eq {
|
||||
isEq,
|
||||
},
|
||||
Hash {
|
||||
hash: hashSet,
|
||||
},
|
||||
]
|
||||
|
||||
isEq : Set k, Set k -> Bool | k has Hash & Eq
|
||||
|
@ -46,6 +46,9 @@ isEq = \xs, ys ->
|
|||
else
|
||||
Break Bool.false
|
||||
|
||||
hashSet : hasher, Set k -> hasher | k has Hash & Eq, hasher has Hasher
|
||||
hashSet = \hasher, @Set inner -> Hash.hash hasher inner
|
||||
|
||||
## Creates a new empty `Set`.
|
||||
## ```
|
||||
## emptySet = Set.empty {}
|
||||
|
@ -353,3 +356,26 @@ expect
|
|||
|> insert 9
|
||||
|
||||
x == fromList (toList x)
|
||||
|
||||
expect
|
||||
orderOne : Set Nat
|
||||
orderOne =
|
||||
single 1
|
||||
|> insert 2
|
||||
|
||||
orderTwo : Set Nat
|
||||
orderTwo =
|
||||
single 2
|
||||
|> insert 1
|
||||
|
||||
wrapperOne : Set (Set Nat)
|
||||
wrapperOne =
|
||||
single orderOne
|
||||
|> insert orderTwo
|
||||
|
||||
wrapperTwo : Set (Set Nat)
|
||||
wrapperTwo =
|
||||
single orderTwo
|
||||
|> insert orderOne
|
||||
|
||||
wrapperOne == wrapperTwo
|
||||
|
|
|
@ -1,28 +1,28 @@
|
|||
procedure Dict.1 (Dict.515):
|
||||
let Dict.518 : List {[], []} = Array [];
|
||||
let Dict.525 : U64 = 0i64;
|
||||
let Dict.526 : U64 = 8i64;
|
||||
let Dict.519 : List U64 = CallByName List.11 Dict.525 Dict.526;
|
||||
let Dict.522 : I8 = CallByName Dict.34;
|
||||
let Dict.523 : U64 = 8i64;
|
||||
let Dict.520 : List I8 = CallByName List.11 Dict.522 Dict.523;
|
||||
let Dict.521 : U64 = 0i64;
|
||||
let Dict.517 : {List {[], []}, List U64, List I8, U64} = Struct {Dict.518, Dict.519, Dict.520, Dict.521};
|
||||
ret Dict.517;
|
||||
procedure Dict.1 (Dict.536):
|
||||
let Dict.546 : List {[], []} = Array [];
|
||||
let Dict.553 : U64 = 0i64;
|
||||
let Dict.554 : U64 = 8i64;
|
||||
let Dict.547 : List U64 = CallByName List.11 Dict.553 Dict.554;
|
||||
let Dict.550 : I8 = CallByName Dict.36;
|
||||
let Dict.551 : U64 = 8i64;
|
||||
let Dict.548 : List I8 = CallByName List.11 Dict.550 Dict.551;
|
||||
let Dict.549 : U64 = 0i64;
|
||||
let Dict.545 : {List {[], []}, List U64, List I8, U64} = Struct {Dict.546, Dict.547, Dict.548, Dict.549};
|
||||
ret Dict.545;
|
||||
|
||||
procedure Dict.34 ():
|
||||
let Dict.524 : I8 = -128i64;
|
||||
ret Dict.524;
|
||||
procedure Dict.36 ():
|
||||
let Dict.552 : I8 = -128i64;
|
||||
ret Dict.552;
|
||||
|
||||
procedure Dict.4 (Dict.504):
|
||||
let Dict.85 : U64 = StructAtIndex 3 Dict.504;
|
||||
let #Derived_gen.2 : List {[], []} = StructAtIndex 0 Dict.504;
|
||||
procedure Dict.4 (Dict.543):
|
||||
let Dict.97 : U64 = StructAtIndex 3 Dict.543;
|
||||
let #Derived_gen.2 : List {[], []} = StructAtIndex 0 Dict.543;
|
||||
dec #Derived_gen.2;
|
||||
let #Derived_gen.1 : List U64 = StructAtIndex 1 Dict.504;
|
||||
let #Derived_gen.1 : List U64 = StructAtIndex 1 Dict.543;
|
||||
dec #Derived_gen.1;
|
||||
let #Derived_gen.0 : List I8 = StructAtIndex 2 Dict.504;
|
||||
let #Derived_gen.0 : List I8 = StructAtIndex 2 Dict.543;
|
||||
dec #Derived_gen.0;
|
||||
ret Dict.85;
|
||||
ret Dict.97;
|
||||
|
||||
procedure List.11 (List.115, List.116):
|
||||
let List.495 : List I8 = CallByName List.68 List.116;
|
||||
|
|
|
@ -5300,7 +5300,6 @@ pub struct CopiedImport {
|
|||
pub rigid: Vec<Variable>,
|
||||
pub flex_able: Vec<Variable>,
|
||||
pub rigid_able: Vec<Variable>,
|
||||
pub translations: Vec<(Variable, Variable)>,
|
||||
pub registered: Vec<Variable>,
|
||||
}
|
||||
|
||||
|
@ -5320,7 +5319,6 @@ struct CopyImportEnv<'a> {
|
|||
rigid: Vec<Variable>,
|
||||
flex_able: Vec<Variable>,
|
||||
rigid_able: Vec<Variable>,
|
||||
translations: Vec<(Variable, Variable)>,
|
||||
registered: Vec<Variable>,
|
||||
}
|
||||
|
||||
|
@ -5348,7 +5346,6 @@ pub fn copy_import_to(
|
|||
rigid: Vec::new(),
|
||||
flex_able: Vec::new(),
|
||||
rigid_able: Vec::new(),
|
||||
translations: Vec::new(),
|
||||
registered: Vec::new(),
|
||||
};
|
||||
|
||||
|
@ -5362,7 +5359,6 @@ pub fn copy_import_to(
|
|||
rigid,
|
||||
flex_able,
|
||||
rigid_able,
|
||||
translations,
|
||||
registered,
|
||||
target: _,
|
||||
bookkeep_unspecialized_lambda_sets: _,
|
||||
|
@ -5374,7 +5370,6 @@ pub fn copy_import_to(
|
|||
rigid,
|
||||
flex_able,
|
||||
rigid_able,
|
||||
translations,
|
||||
registered,
|
||||
}
|
||||
};
|
||||
|
@ -5668,13 +5663,21 @@ fn copy_import_to_help(env: &mut CopyImportEnv<'_>, max_rank: Rank, var: Variabl
|
|||
let name = env.source.field_names[name_index.index as usize].clone();
|
||||
let new_name_index = SubsIndex::push_new(&mut env.target.field_names, name);
|
||||
|
||||
env.target
|
||||
.set(copy, make_descriptor(RigidVar(new_name_index)));
|
||||
// If we are copying the import as generalized, we can keep it as rigid.
|
||||
// Otherwise we must make it flex, as this is copying to a non-generalized site.
|
||||
//
|
||||
// The rigid distinction is never necessary for imports, since their types have already
|
||||
// been checked completely.
|
||||
let content = if max_rank.is_generalized() {
|
||||
RigidVar(new_name_index)
|
||||
} else {
|
||||
FlexVar(Some(new_name_index))
|
||||
};
|
||||
|
||||
env.target.set(copy, make_descriptor(content));
|
||||
|
||||
env.rigid.push(copy);
|
||||
|
||||
env.translations.push((var, copy));
|
||||
|
||||
copy
|
||||
}
|
||||
|
||||
|
@ -5687,15 +5690,21 @@ fn copy_import_to_help(env: &mut CopyImportEnv<'_>, max_rank: Rank, var: Variabl
|
|||
env.source.get_subs_slice(abilities).iter().copied(),
|
||||
);
|
||||
|
||||
env.target.set(
|
||||
copy,
|
||||
make_descriptor(RigidAbleVar(new_name_index, new_abilities)),
|
||||
);
|
||||
// If we are copying the import as generalized, we can keep it as rigid.
|
||||
// Otherwise we must make it flex, as this is copying to a non-generalized site.
|
||||
//
|
||||
// The rigid distinction is never necessary for imports, since their types have already
|
||||
// been checked completely.
|
||||
let content = if max_rank.is_generalized() {
|
||||
RigidAbleVar(new_name_index, new_abilities)
|
||||
} else {
|
||||
FlexAbleVar(Some(new_name_index), new_abilities)
|
||||
};
|
||||
|
||||
env.target.set(copy, make_descriptor(content));
|
||||
|
||||
env.rigid_able.push(copy);
|
||||
|
||||
env.translations.push((var, copy));
|
||||
|
||||
copy
|
||||
}
|
||||
|
||||
|
|
|
@ -3,22 +3,22 @@
|
|||
app "test" provides [main] to "./platform"
|
||||
|
||||
f = \{} ->
|
||||
#^{-1} <1527><116>{} -<119>[[f(1)]]-> <115>[Ok <1535>{}]<79>*
|
||||
#^{-1} <1606><116>{} -<119>[[f(1)]]-> <115>[Ok <1614>{}]<79>*
|
||||
when g {} is
|
||||
# ^ <1517><1535>{} -<1525>[[g(2)]]-> <71>[Ok <1535>{}]<101>*
|
||||
# ^ <1596><1614>{} -<1604>[[g(2)]]-> <71>[Ok <1614>{}]<101>*
|
||||
_ -> Ok {}
|
||||
|
||||
g = \{} ->
|
||||
#^{-1} <1517><1535>{} -<1525>[[g(2)]]-> <71>[Ok <1535>{}]<101>*
|
||||
#^{-1} <1596><1614>{} -<1604>[[g(2)]]-> <71>[Ok <1614>{}]<101>*
|
||||
when h {} is
|
||||
# ^ <1522><1535>{} -<1530>[[h(3)]]-> <93>[Ok <1535>{}]<123>*
|
||||
# ^ <1601><1614>{} -<1609>[[h(3)]]-> <93>[Ok <1614>{}]<123>*
|
||||
_ -> Ok {}
|
||||
|
||||
h = \{} ->
|
||||
#^{-1} <1522><1535>{} -<1530>[[h(3)]]-> <93>[Ok <1535>{}]<123>*
|
||||
#^{-1} <1601><1614>{} -<1609>[[h(3)]]-> <93>[Ok <1614>{}]<123>*
|
||||
when f {} is
|
||||
# ^ <1527><116>{} -<119>[[f(1)]]-> <115>[Ok <1535>{}]<79>*
|
||||
# ^ <1606><116>{} -<119>[[f(1)]]-> <115>[Ok <1614>{}]<79>*
|
||||
_ -> Ok {}
|
||||
|
||||
main = f {}
|
||||
# ^ <1537><132>{} -<135>[[f(1)]]-> <137>[Ok <1535>{}]<1536>w_a
|
||||
# ^ <1616><132>{} -<135>[[f(1)]]-> <137>[Ok <1614>{}]<1615>w_a
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue