mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-27 05:49:08 +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),
|
data : List (T k v),
|
||||||
size : Nat,
|
size : Nat,
|
||||||
} | k has Hash & Eq
|
} | 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.
|
## Return an empty dictionary.
|
||||||
## ```
|
## ```
|
||||||
|
@ -747,6 +771,71 @@ expect
|
||||||
|
|
||||||
val == Ok "bar"
|
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
|
expect
|
||||||
val =
|
val =
|
||||||
empty {}
|
empty {}
|
||||||
|
|
|
@ -20,19 +20,19 @@ interface Set
|
||||||
Bool.{ Bool, Eq },
|
Bool.{ Bool, Eq },
|
||||||
Dict.{ Dict },
|
Dict.{ Dict },
|
||||||
Num.{ Nat },
|
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))
|
## Provides a [set](https://en.wikipedia.org/wiki/Set_(abstract_data_type))
|
||||||
## type which stores a collection of unique values, without any ordering
|
## 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 [
|
has [
|
||||||
Eq {
|
Eq {
|
||||||
isEq,
|
isEq,
|
||||||
},
|
},
|
||||||
|
Hash {
|
||||||
|
hash: hashSet,
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
isEq : Set k, Set k -> Bool | k has Hash & Eq
|
isEq : Set k, Set k -> Bool | k has Hash & Eq
|
||||||
|
@ -46,6 +46,9 @@ isEq = \xs, ys ->
|
||||||
else
|
else
|
||||||
Break Bool.false
|
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`.
|
## Creates a new empty `Set`.
|
||||||
## ```
|
## ```
|
||||||
## emptySet = Set.empty {}
|
## emptySet = Set.empty {}
|
||||||
|
@ -353,3 +356,26 @@ expect
|
||||||
|> insert 9
|
|> insert 9
|
||||||
|
|
||||||
x == fromList (toList x)
|
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):
|
procedure Dict.1 (Dict.536):
|
||||||
let Dict.518 : List {[], []} = Array [];
|
let Dict.546 : List {[], []} = Array [];
|
||||||
let Dict.525 : U64 = 0i64;
|
let Dict.553 : U64 = 0i64;
|
||||||
let Dict.526 : U64 = 8i64;
|
let Dict.554 : U64 = 8i64;
|
||||||
let Dict.519 : List U64 = CallByName List.11 Dict.525 Dict.526;
|
let Dict.547 : List U64 = CallByName List.11 Dict.553 Dict.554;
|
||||||
let Dict.522 : I8 = CallByName Dict.34;
|
let Dict.550 : I8 = CallByName Dict.36;
|
||||||
let Dict.523 : U64 = 8i64;
|
let Dict.551 : U64 = 8i64;
|
||||||
let Dict.520 : List I8 = CallByName List.11 Dict.522 Dict.523;
|
let Dict.548 : List I8 = CallByName List.11 Dict.550 Dict.551;
|
||||||
let Dict.521 : U64 = 0i64;
|
let Dict.549 : U64 = 0i64;
|
||||||
let Dict.517 : {List {[], []}, List U64, List I8, U64} = Struct {Dict.518, Dict.519, Dict.520, Dict.521};
|
let Dict.545 : {List {[], []}, List U64, List I8, U64} = Struct {Dict.546, Dict.547, Dict.548, Dict.549};
|
||||||
ret Dict.517;
|
ret Dict.545;
|
||||||
|
|
||||||
procedure Dict.34 ():
|
procedure Dict.36 ():
|
||||||
let Dict.524 : I8 = -128i64;
|
let Dict.552 : I8 = -128i64;
|
||||||
ret Dict.524;
|
ret Dict.552;
|
||||||
|
|
||||||
procedure Dict.4 (Dict.504):
|
procedure Dict.4 (Dict.543):
|
||||||
let Dict.85 : U64 = StructAtIndex 3 Dict.504;
|
let Dict.97 : U64 = StructAtIndex 3 Dict.543;
|
||||||
let #Derived_gen.2 : List {[], []} = StructAtIndex 0 Dict.504;
|
let #Derived_gen.2 : List {[], []} = StructAtIndex 0 Dict.543;
|
||||||
dec #Derived_gen.2;
|
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;
|
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;
|
dec #Derived_gen.0;
|
||||||
ret Dict.85;
|
ret Dict.97;
|
||||||
|
|
||||||
procedure List.11 (List.115, List.116):
|
procedure List.11 (List.115, List.116):
|
||||||
let List.495 : List I8 = CallByName List.68 List.116;
|
let List.495 : List I8 = CallByName List.68 List.116;
|
||||||
|
|
|
@ -5300,7 +5300,6 @@ pub struct CopiedImport {
|
||||||
pub rigid: Vec<Variable>,
|
pub rigid: Vec<Variable>,
|
||||||
pub flex_able: Vec<Variable>,
|
pub flex_able: Vec<Variable>,
|
||||||
pub rigid_able: Vec<Variable>,
|
pub rigid_able: Vec<Variable>,
|
||||||
pub translations: Vec<(Variable, Variable)>,
|
|
||||||
pub registered: Vec<Variable>,
|
pub registered: Vec<Variable>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5320,7 +5319,6 @@ struct CopyImportEnv<'a> {
|
||||||
rigid: Vec<Variable>,
|
rigid: Vec<Variable>,
|
||||||
flex_able: Vec<Variable>,
|
flex_able: Vec<Variable>,
|
||||||
rigid_able: Vec<Variable>,
|
rigid_able: Vec<Variable>,
|
||||||
translations: Vec<(Variable, Variable)>,
|
|
||||||
registered: Vec<Variable>,
|
registered: Vec<Variable>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5348,7 +5346,6 @@ pub fn copy_import_to(
|
||||||
rigid: Vec::new(),
|
rigid: Vec::new(),
|
||||||
flex_able: Vec::new(),
|
flex_able: Vec::new(),
|
||||||
rigid_able: Vec::new(),
|
rigid_able: Vec::new(),
|
||||||
translations: Vec::new(),
|
|
||||||
registered: Vec::new(),
|
registered: Vec::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -5362,7 +5359,6 @@ pub fn copy_import_to(
|
||||||
rigid,
|
rigid,
|
||||||
flex_able,
|
flex_able,
|
||||||
rigid_able,
|
rigid_able,
|
||||||
translations,
|
|
||||||
registered,
|
registered,
|
||||||
target: _,
|
target: _,
|
||||||
bookkeep_unspecialized_lambda_sets: _,
|
bookkeep_unspecialized_lambda_sets: _,
|
||||||
|
@ -5374,7 +5370,6 @@ pub fn copy_import_to(
|
||||||
rigid,
|
rigid,
|
||||||
flex_able,
|
flex_able,
|
||||||
rigid_able,
|
rigid_able,
|
||||||
translations,
|
|
||||||
registered,
|
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 name = env.source.field_names[name_index.index as usize].clone();
|
||||||
let new_name_index = SubsIndex::push_new(&mut env.target.field_names, name);
|
let new_name_index = SubsIndex::push_new(&mut env.target.field_names, name);
|
||||||
|
|
||||||
env.target
|
// If we are copying the import as generalized, we can keep it as rigid.
|
||||||
.set(copy, make_descriptor(RigidVar(new_name_index)));
|
// 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.rigid.push(copy);
|
||||||
|
|
||||||
env.translations.push((var, copy));
|
|
||||||
|
|
||||||
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.source.get_subs_slice(abilities).iter().copied(),
|
||||||
);
|
);
|
||||||
|
|
||||||
env.target.set(
|
// If we are copying the import as generalized, we can keep it as rigid.
|
||||||
copy,
|
// Otherwise we must make it flex, as this is copying to a non-generalized site.
|
||||||
make_descriptor(RigidAbleVar(new_name_index, new_abilities)),
|
//
|
||||||
);
|
// 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.rigid_able.push(copy);
|
||||||
|
|
||||||
env.translations.push((var, copy));
|
|
||||||
|
|
||||||
copy
|
copy
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,22 +3,22 @@
|
||||||
app "test" provides [main] to "./platform"
|
app "test" provides [main] to "./platform"
|
||||||
|
|
||||||
f = \{} ->
|
f = \{} ->
|
||||||
#^{-1} <1527><116>{} -<119>[[f(1)]]-> <115>[Ok <1535>{}]<79>*
|
#^{-1} <1606><116>{} -<119>[[f(1)]]-> <115>[Ok <1614>{}]<79>*
|
||||||
when g {} is
|
when g {} is
|
||||||
# ^ <1517><1535>{} -<1525>[[g(2)]]-> <71>[Ok <1535>{}]<101>*
|
# ^ <1596><1614>{} -<1604>[[g(2)]]-> <71>[Ok <1614>{}]<101>*
|
||||||
_ -> Ok {}
|
_ -> Ok {}
|
||||||
|
|
||||||
g = \{} ->
|
g = \{} ->
|
||||||
#^{-1} <1517><1535>{} -<1525>[[g(2)]]-> <71>[Ok <1535>{}]<101>*
|
#^{-1} <1596><1614>{} -<1604>[[g(2)]]-> <71>[Ok <1614>{}]<101>*
|
||||||
when h {} is
|
when h {} is
|
||||||
# ^ <1522><1535>{} -<1530>[[h(3)]]-> <93>[Ok <1535>{}]<123>*
|
# ^ <1601><1614>{} -<1609>[[h(3)]]-> <93>[Ok <1614>{}]<123>*
|
||||||
_ -> Ok {}
|
_ -> Ok {}
|
||||||
|
|
||||||
h = \{} ->
|
h = \{} ->
|
||||||
#^{-1} <1522><1535>{} -<1530>[[h(3)]]-> <93>[Ok <1535>{}]<123>*
|
#^{-1} <1601><1614>{} -<1609>[[h(3)]]-> <93>[Ok <1614>{}]<123>*
|
||||||
when f {} is
|
when f {} is
|
||||||
# ^ <1527><116>{} -<119>[[f(1)]]-> <115>[Ok <1535>{}]<79>*
|
# ^ <1606><116>{} -<119>[[f(1)]]-> <115>[Ok <1614>{}]<79>*
|
||||||
_ -> Ok {}
|
_ -> Ok {}
|
||||||
|
|
||||||
main = f {}
|
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