mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-03 19:58:18 +00:00
Add some missing Dict and Set functions
Also remove some unnecessary Hash and Eq restrictions
This commit is contained in:
parent
82a2f3eb99
commit
ed9d9b12f5
4 changed files with 104 additions and 5 deletions
|
@ -7,6 +7,7 @@ interface Dict
|
|||
clear,
|
||||
capacity,
|
||||
len,
|
||||
isEmpty,
|
||||
get,
|
||||
contains,
|
||||
insert,
|
||||
|
@ -21,6 +22,8 @@ interface Dict
|
|||
insertAll,
|
||||
keepShared,
|
||||
removeAll,
|
||||
map,
|
||||
joinMap,
|
||||
]
|
||||
imports [
|
||||
Bool.{ Bool, Eq },
|
||||
|
@ -139,12 +142,12 @@ empty = \{} ->
|
|||
## Returns the max number of elements the dictionary can hold before requiring a rehash.
|
||||
## ```
|
||||
## foodDict =
|
||||
## Dict.empty {}
|
||||
## |> Dict.insert "apple" "fruit"
|
||||
## Dict.empty {}
|
||||
## |> Dict.insert "apple" "fruit"
|
||||
##
|
||||
## capacityOfDict = Dict.capacity foodDict
|
||||
## ```
|
||||
capacity : Dict k v -> Nat | k has Hash & Eq
|
||||
capacity : Dict * * -> Nat
|
||||
capacity = \@Dict { dataIndices } ->
|
||||
cap = List.len dataIndices
|
||||
|
||||
|
@ -192,10 +195,20 @@ fromList = \data ->
|
|||
## |> Dict.len
|
||||
## |> Bool.isEq 3
|
||||
## ```
|
||||
len : Dict k v -> Nat | k has Hash & Eq
|
||||
len : Dict * * -> Nat
|
||||
len = \@Dict { size } ->
|
||||
size
|
||||
|
||||
## Check if the dictinoary is empty.
|
||||
## ```
|
||||
## Dict.isEmpty (Dict.empty {} |> Dict.insert "key" 42)
|
||||
##
|
||||
## Dict.isEmpty (Dict.empty {})
|
||||
## ```
|
||||
isEmpty : Dict * * -> Bool
|
||||
isEmpty = \@Dict { size } ->
|
||||
size == 0
|
||||
|
||||
## Clears all elements from a dictionary keeping around the allocation if it isn't huge.
|
||||
## ```
|
||||
## songs =
|
||||
|
@ -225,6 +238,28 @@ clear = \@Dict { metadata, dataIndices, data } ->
|
|||
size: 0,
|
||||
}
|
||||
|
||||
## Convert each value in the dictionary to something new, by calling a conversion
|
||||
## function on each of them which receives both the key and the old value. Then return a
|
||||
## new dictionary containing the same keys and the converted values.
|
||||
map : Dict k a, (k, a -> b) -> Dict k b | k has Hash & Eq, b has Hash & Eq
|
||||
map = \dict, transform ->
|
||||
init = withCapacity (capacity dict)
|
||||
|
||||
walk dict init \answer, k, v ->
|
||||
insert answer k (transform k v)
|
||||
|
||||
## Like [Dict.map], except the transformation function wraps the return value
|
||||
## in a dictionary. At the end, all the dictionaries get joined together
|
||||
## (using [Dict.insertAll]) into one dictionary.
|
||||
##
|
||||
## You may know a similar function named `concatMap` in other languages.
|
||||
joinMap : Dict a b, (a, b -> Dict x y) -> Dict x y | a has Hash & Eq, x has Hash & Eq
|
||||
joinMap = \dict, transform ->
|
||||
init = withCapacity (capacity dict) # Might be a pessimization
|
||||
|
||||
walk dict init \answer, k, v ->
|
||||
insertAll answer (transform k v)
|
||||
|
||||
## Iterate through the keys and values in the dictionary and call the provided
|
||||
## function with signature `state, k, v -> state` for each value, with an
|
||||
## initial `state` value provided for the first call.
|
||||
|
|
|
@ -208,6 +208,9 @@ interface List
|
|||
## * Even when copying is faster, other list operations may still be slightly slower with persistent data structures. For example, even if it were a persistent data structure, [List.map], [List.walk], and [List.keepIf] would all need to traverse every element in the list and build up the result from scratch. These operations are all
|
||||
## * Roc's compiler optimizes many list operations into in-place mutations behind the scenes, depending on how the list is being used. For example, [List.map], [List.keepIf], and [List.set] can all be optimized to perform in-place mutations.
|
||||
## * If possible, it is usually best for performance to use large lists in a way where the optimizer can turn them into in-place mutations. If this is not possible, a persistent data structure might be faster - but this is a rare enough scenario that it would not be good for the average Roc program's performance if this were the way [List] worked by default. Instead, you can look outside Roc's standard modules for an implementation of a persistent data structure - likely built using [List] under the hood!
|
||||
|
||||
# separator so List.isEmpty doesn't absorb the above into its doc comment
|
||||
|
||||
## Check if the list is empty.
|
||||
## ```
|
||||
## List.isEmpty [1, 2, 3]
|
||||
|
|
|
@ -7,6 +7,8 @@ interface Set
|
|||
walkUntil,
|
||||
insert,
|
||||
len,
|
||||
isEmpty,
|
||||
capacity,
|
||||
remove,
|
||||
contains,
|
||||
toList,
|
||||
|
@ -14,6 +16,8 @@ interface Set
|
|||
union,
|
||||
intersection,
|
||||
difference,
|
||||
map,
|
||||
joinMap,
|
||||
]
|
||||
imports [
|
||||
List,
|
||||
|
@ -59,6 +63,13 @@ hashSet = \hasher, @Set inner -> Hash.hash hasher inner
|
|||
empty : {} -> Set k | k has Hash & Eq
|
||||
empty = \{} -> @Set (Dict.empty {})
|
||||
|
||||
## Return a dictionary with space allocated for a number of entries. This
|
||||
## may provide a performance optimization if you know how many entries will be
|
||||
## inserted.
|
||||
withCapacity : Nat -> Set k | k has Hash & Eq
|
||||
withCapacity = \cap ->
|
||||
@Set (Dict.withCapacity cap)
|
||||
|
||||
## Creates a new `Set` with a single value.
|
||||
## ```
|
||||
## singleItemSet = Set.single "Apple"
|
||||
|
@ -115,10 +126,32 @@ expect
|
|||
##
|
||||
## expect countValues == 3
|
||||
## ```
|
||||
len : Set k -> Nat | k has Hash & Eq
|
||||
len : Set * -> Nat
|
||||
len = \@Set dict ->
|
||||
Dict.len dict
|
||||
|
||||
## Returns the max number of elements the set can hold before requiring a rehash.
|
||||
## ```
|
||||
## foodSet =
|
||||
## Set.empty {}
|
||||
## |> Set.insert "apple"
|
||||
##
|
||||
## capacityOfSet = Set.capacity foodSet
|
||||
## ```
|
||||
capacity : Set * -> Nat
|
||||
capacity = \@Set dict ->
|
||||
Dict.capacity dict
|
||||
|
||||
## Check if the set is empty.
|
||||
## ```
|
||||
## Set.isEmpty (Set.empty {} |> Set.insert 42)
|
||||
##
|
||||
## Set.isEmpty (Set.empty {})
|
||||
## ```
|
||||
isEmpty : Set * -> Bool
|
||||
isEmpty = \@Set dict ->
|
||||
Dict.isEmpty dict
|
||||
|
||||
# Inserting a duplicate key has no effect on length.
|
||||
expect
|
||||
actual =
|
||||
|
@ -261,6 +294,28 @@ 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)
|
||||
|
||||
## Convert each value in the set to something new, by calling a conversion
|
||||
## function on each of them which receives the old value. Then return a
|
||||
## new set containing the converted values.
|
||||
map : Set a, (a -> b) -> Set b | a has Hash & Eq, b has Hash & Eq
|
||||
map = \set, transform ->
|
||||
init = withCapacity (capacity set)
|
||||
|
||||
walk set init \answer, k ->
|
||||
insert answer (transform k)
|
||||
|
||||
## Like [Set.map], except the transformation function wraps the return value
|
||||
## in a set. At the end, all the sets get joined together
|
||||
## (using [Set.union]) into one set.
|
||||
##
|
||||
## You may know a similar function named `concatMap` in other languages.
|
||||
joinMap : Set a, (a -> Set b) -> Set b | a has Hash & Eq, b has Hash & Eq
|
||||
joinMap = \set, transform ->
|
||||
init = withCapacity (capacity set) # Might be a pessimization
|
||||
|
||||
walk set init \answer, k ->
|
||||
union answer (transform k)
|
||||
|
||||
## Iterate through the values of a given `Set` and build a value, can stop
|
||||
## iterating part way through the collection.
|
||||
## ```
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue