8.6 Sets
Immutable sets can be constructed using the syntax {val_expr, ...}, which creates a set containing the values of the val_exprs. More precisely, a use of curly braces with no preceding expression is parsed as an implicit use of the #%braces form.
A set is indexable, and […] after a set expression with an expression for a value checks for membership: the result is a boolean indicating whether the value is in the set. Mutable sets can be updated with a combination of […] and the := operator, where a #false result on the right-hand side of := removes an element from a set, and any other right-hand side result causes the value to be included in the set. (Use ++ to functionally add to an immutable set.) These uses of […] are implemented by #%index. A set can be used as sequence, in which case it supplies its elements in an unspecified order.
annotation | |
| |
annotation | |
| |
annotation | |
| |
annotation | |
| |
annotation | |
| |
annotation | |
| |
annotation | |
| |
annotation | |
| |
annotation | |
| |
annotation | |
| |
annotation | |
| |
annotation | |
The of and now_of annotation variants match a set whose elements satisfy annot, where satisfaction of the annotation is confirmed by immediately checking all elements. No future obligation is attached to a set satisfying the annotation, so in the case of MutableSet.now_of, no static information is associated with value access using […].
The later_of annotation variants create a converter annotation given an annotations for elements; satisfaction of those annotations is confirmed only on demand, both for elements that are extracted from the set and for elements added or appended to the set. For Set.later_of, the key and value annotations must be predicate annotations. Since an element annotation is checked on every access, its static information is associated with access using […].
The Set.by and MutableSet.by annotation variants match only sets that use the hash and equality functions specified by key_comp.
Static information associated by Set, etc., makes an expression acceptable to for in static mode.
expression | ||||||||||||
| ||||||||||||
| ||||||||||||
repetition | ||||||||||||
| ||||||||||||
| ||||||||||||
| ||||||||||||
| ||||||||||||
| ||||||||||||
| ||||||||||||
| ||||||||||||
| ||||||||||||
function | ||||||||||||
| ||||||||||||
expression | ||||||||||||
| ||||||||||||
| ||||||||||||
expression | ||||||||||||
| ||||||||||||
repetition | ||||||||||||
Note that Set{} and Set() produce an empty set while {…} does not, since {} produces an empty map instead.
The Set.by variants create a set that uses the equality and hashing functions specified by key_comp.
> s
{1, 2, "x", "y"}
> s["x"]
#true
> s[1]
#true
> s[42]
#false
> Set("x", 1, "y", 2)
{1, 2, "x", "y"}
binding operator | ||||||||
| ||||||||
binding operator | ||||||||
| ||||||||
binding operator | ||||||||
| ||||||||
binding operator | ||||||||
| ||||||||
binding operator | ||||||||
| ||||||||
| ||||||||
binding operator | ||||||||
| ||||||||
| ||||||||
binding operator | ||||||||
| ||||||||
| ||||||||
binding operator | ||||||||
| ||||||||
| ||||||||
binding operator | ||||||||
| ||||||||
binding operator | ||||||||
| ||||||||
binding operator | ||||||||
| ||||||||
binding operator | ||||||||
| ||||||||
| ||||||||
| ||||||||
|
The Set binding forms match only immutable sets, while ReadableSet forms match both immutable and mutable sets. For ReadableSet, the & set_bind will match a snapshot (in the sense of Set.snapshot) of the rest of the set. The Set.by binding forms match only immutable sets constructed using key_comp.
def: value does not satisfy annotation
value: {"x"}
annotation: matching(Set{"x", "y""x", "y"})
> rst
{"b", "c"}
> [val, ...]
["c", "b"]
The Set.by reducer creates a set that uses the equality and hashing functions specified by key_comp.
expression | |
| |
| |
function | |
| |
| |
expression | |
| |
| |
expression | |
Note that ... and & are not supported for construction mutable sets, only immutable sets.
> def m = MutableSet{"x", 1, "y", 2}
> m
MutableSet{1, 2, "x", "y"}
> m["x"]
#true
> m["x"] := #false
> m
MutableSet{1, 2, "y"}
> m["x"] := #true
> m
MutableSet{1, 2, "x", "y"}
expression | |
| |
| |
function | |
| |
| |
expression | |
| |
| |
expression | |
Like MutableSet, but creates a set where an element is removed from the set by a garbage collection when the element is reachable only by enumerating the set’s elements.
value | |
| |
binding operator | |
| |
value | |
| |
binding operator | |
The ReadableSet.empty binding form matches an empty set whether it is mutable or immutable.
Corresponding to the binding forms, Set.empty and ReadableSet.empty are bound to Set{} with appropriate static information.
Set{}
| Set.empty: "empty set"
| _: #false
"empty set"
> match MutableSet()
| Set.empty: "empty immutable set"
| _: #false
#false
> match MutableSet()
| ReadableSet.empty: "empty set for now"
| _: #false
"empty set for now"
method | |
|
> Set.length({"a", "b"})
2
> Set.length(Set{})
0
2
0
method | |
| |
method | |
|
#true
> {"a", "b"}.has_element("a")
#true
> {"a", "b"}["a"]
#true
method | |
| |
method | |
Even when another_st uses a different map configuration than st, the map configuration of st is preserved in the result set. Conceptually, in the binary case, each element from the right set is added to the left set.
{1, 2, 3, 4}
{1, 2, 3, 4}
{1, 2, 3, 4}
Set.by(is_same_number_or_object){2, 3},
)
{1, 2, 3, 4}
Set.by(is_same_number_or_object){2, 3},
)
{1, 2, 3, 4}
> {1, 2, 3}
++ Set.by(is_same_number_or_object){2, 3}
{1, 2, 3, 4}
Even when some another_st uses a different map configuration than st, the map configuration of st is preserved in the result set.
{3}
Set.by(is_same_number_or_object){2, 3},
)
{3}
{1, 3}
{1, 2, 3}
> def s = MutableSet{1, 2, 3}
> s
MutableSet{2, 3}
> s[1] := #true
> s
MutableSet{1, 2, 3}
> def s = MutableSet{1, 2, 3}
> s
MutableSet{1, 3}
method | |||
[1, 2, 3]
method | |
> def s = MutableSet{"a", "b"}
> s.copy()
MutableSet{"a", "b"}
method | |
|
> def s = MutableSet{"a", "b"}
> s.snapshot()
{"a", "b"}
method | |