add walkUntil and use it to implement set equality

This commit is contained in:
Brendan Hansknecht 2022-11-21 17:08:30 -08:00
parent 4159b83214
commit cad7d8b4e9
No known key found for this signature in database
GPG Key ID: 0EA784685083E75B
3 changed files with 96 additions and 16 deletions

View File

@ -13,6 +13,7 @@ interface Dict
remove,
update,
walk,
walkUntil,
toList,
fromList,
keys,
@ -190,6 +191,21 @@ walk : Dict k v, state, (state, k, v -> state) -> state | k has Hash & Eq
walk = \@Dict { data }, initialState, transform ->
List.walk data initialState (\state, T k v -> transform state k v)
## Same as [Dict.walk], except you can stop walking early.
##
## ## Performance Details
##
## Compared to [Dict.walk], this can potentially visit fewer elements (which can
## improve performance) at the cost of making each step take longer.
## However, the added cost to each step is extremely small, and can easily
## be outweighed if it results in skipping even a small number of elements.
##
## As such, it is typically better for performance to use this over [Dict.walk]
## if returning `Break` earlier than the last element is expected to be common.
walkUntil : Dict k v, state, (state, k, v -> [Continue state, Break state]) -> state | k has Hash & Eq
walkUntil = \@Dict { data }, initialState, transform ->
List.walkUntil data initialState (\state, T k v -> transform state k v)
## Get the value for a given key. If there is a value for the specified key it
## will return [Ok value], otherwise return [Err KeyNotFound].
##

View File

@ -33,7 +33,15 @@ Set k := Dict.Dict k {}
]
isEq : Set k, Set k -> Bool | k has Hash & Eq
isEq = \_, _ -> Bool.true
isEq = \xs, ys ->
if len xs != len ys then
Bool.false
else
walkUntil xs Bool.true \_, elem ->
if contains ys elem then
Continue Bool.true
else
Break Bool.false
## An empty set.
empty : Set k | k has Hash & Eq
@ -114,3 +122,57 @@ difference = \@Set dict1, @Set dict2 ->
walk : Set k, state, (state, k -> state) -> state | k has Hash & Eq
walk = \@Set dict, state, step ->
Dict.walk dict state (\s, k, _ -> step s k)
walkUntil : Set k, state, (state, k -> [Continue state, Break state]) -> state | k has Hash & Eq
walkUntil = \@Set dict, state, step ->
Dict.walkUntil dict state (\s, k, _ -> step s k)
expect
first =
single "Keep Me"
|> insert "And Me"
|> insert "Remove Me"
second =
single "Remove Me"
|> insert "I do nothing..."
expected =
single "Keep Me"
|> insert "And Me"
difference first second == expected
expect
first =
single "Keep Me"
|> insert "And Me"
|> insert "Remove Me"
second =
single "Remove Me"
|> insert "I do nothing..."
expected =
single "Keep Me"
|> insert "And Me"
difference first second == expected
expect
first =
single 1
|> insert 2
second =
single 1
|> insert 3
|> insert 4
expected =
single 1
|> insert 2
|> insert 3
|> insert 4
union first second == expected

View File

@ -1409,20 +1409,21 @@ define_builtins! {
9 DICT_REMOVE: "remove"
10 DICT_WALK: "walk"
11 DICT_FROM_LIST: "fromList"
12 DICT_TO_LIST: "toList"
13 DICT_KEYS: "keys"
14 DICT_VALUES: "values"
11 DICT_WALK_UNTIL: "walkUntil"
12 DICT_FROM_LIST: "fromList"
13 DICT_TO_LIST: "toList"
14 DICT_KEYS: "keys"
15 DICT_VALUES: "values"
15 DICT_INSERT_ALL: "insertAll" // union
16 DICT_KEEP_SHARED: "keepShared" // intersection
17 DICT_REMOVE_ALL: "removeAll" // difference
16 DICT_INSERT_ALL: "insertAll" // union
17 DICT_KEEP_SHARED: "keepShared" // intersection
18 DICT_REMOVE_ALL: "removeAll" // difference
18 DICT_WITH_CAPACITY: "withCapacity"
19 DICT_CAPACITY: "capacity"
20 DICT_UPDATE: "update"
19 DICT_WITH_CAPACITY: "withCapacity"
20 DICT_CAPACITY: "capacity"
21 DICT_UPDATE: "update"
21 DICT_LIST_GET_UNSAFE: "listGetUnsafe"
22 DICT_LIST_GET_UNSAFE: "listGetUnsafe"
}
9 SET: "Set" => {
0 SET_SET: "Set" exposed_type=true // the Set.Set type alias
@ -1437,10 +1438,11 @@ define_builtins! {
9 SET_TO_LIST: "toList"
10 SET_FROM_LIST: "fromList"
11 SET_WALK: "walk"
12 SET_WALK_USER_FUNCTION: "#walk_user_function"
13 SET_CONTAINS: "contains"
14 SET_TO_DICT: "toDict"
15 SET_CAPACITY: "capacity"
12 SET_WALK_UNTIL: "walkUntil"
13 SET_WALK_USER_FUNCTION: "#walk_user_function"
14 SET_CONTAINS: "contains"
15 SET_TO_DICT: "toDict"
16 SET_CAPACITY: "capacity"
}
10 BOX: "Box" => {
0 BOX_BOX_TYPE: "Box" exposed_apply_type=true // the Box.Box opaque type