Iterate support is provided by a separate ASDF system, FSet/Iterate, so as not to pull in Iterate as
a dependency if you’re not using it. To load it, do (ql:quickload "fset/iterate").
There are two symbol collisions between packages fset/iterate and iterate that you
will need to deal with. One is relatively straightforward: fset/iterate exports a different
version of unioning; see the description below.
The other has to do with the symbol with. Astonishingly, though both FSet and Iterate export
a symbol with, they do not conflict in practice. Iterate doesn’t fdefine with, but
uses it as a clause head, part of its syntax. Since it would never make sense to call
fset:with without doing something with its return value, an fset:with call will never
appear at top level within the body of an iter form, so iter could never mistake it
for a clause head. That means you actually can write something like this:
(iter ... (with foo = (with some-set new-element)) ... )
although, to keep your fellow developers’ heads from exploding, you might be better advised to
package-qualify the two occurrences of with.
[But see this Iterate issue. As of this writing, reloading Iterate could make this stop working; also, that page has an Iterate patch you might need for it to work in all cases.]
With that in mind, I recommend adding the following to any packages in which you want to use FSet’s Iterate support:
(:shadowing-import-from :fset2 #:with) (:shadowing-import-from :fset/iterate #:unioning)
Here are the clauses and accumulators defined by FSet/Iterate:
Yields the elements of set.
Yields the elements of bag. Elements with multiplicities greater than 1 will be repeated that many times.
Yields the pairs of bag, binding var to each element and count to its multiplicity.
Yields the pairs of map, binding key to each key and value to its value.
Yields the elements of seq. The index range can be specified with from/uptrom or downfrom, and/or to, downto, above, or below. step, if supplied, gives the index step.
Yields the elements of coll, which can be any collection which has an iterator method
conforming to the FSet stateful iterator protocol.
FSet’s Iterate support also includes several accumulators for constructing new collections:
Collects values into a set. By default, this is a ch-set organized by compare; supply
init-val to construct a different kind of set.
Collects values into a bag. By default, this is a ch-bag organized by compare; supply
init-val to construct a different kind of bag.
Collects value/count pairs into a bag; that is, on each execution, adds count-expr instances
of expr to the bag. By default, this is a ch-bag organized by compare; supply
init-val to construct a different kind of bag.
Collects values into a seq.
Collects key/value pairs into a map. By default, this is a ch-map organized by
compare; supply init-val to construct a different kind of map. If a key is supplied
more than once, the last value supplied for it is retained.
Collects key/value pairs into a map, collecting the values supplied for each key into a set; that
is, the result is a map whose range values are sets. By default, the map is a ch-map
organized by compare, and the sets are ch-sets organized by compare; supply
init-val to construct a different kind of map (the map’s default must be a set).
Unions sets into a result set. If init-val is provided, the result will be of the same type
and organization; otherwise, it will be of the same type and organization as the first set received,
unless the iteration terminates without executing this clause at all, in which case the result will
be the empty ch-set.
(My recommendation is for fset/iterate:unioning to shadow iter:unioning as described
above; but it’s up to you whether to accept it. Since you’re using FSet, you probably want to avoid
unioning lists, which takes quadratic time. However, FSet’s version doesn’t support the at
keyword, nor does it normally offer the ordering guarantee that iter:unioning does, although
you can get that effect by supplying initial-value (replay-set) and binding expr to
replay sets.)
Intersects sets into a result set. If init-val is provided, the result will be of the same
type and organization; otherwise, it will be of the same type and organization as the first set
received, unless the iteration terminates without executing this clause at all, in which case the
result will be the full set built on ch-set.
Concatenates successive seqs into a result seq.
Map-unions maps into a result map (see Method map-union (map map)). If val-fn is
provided, it is used to combine values corresponding to the same key; the default is to overwrite
the value from the earlier map with the later value. If init-val is provided, the result will
be of the same type and organization; otherwise, it will be of the same type and organization as the
first set received, unless the iteration terminates without executing this clause at all, in which
case the result will be the empty ch-map.
Map-intersects maps into a result map (see Method map-intersection (map map)). If val-fn
is provided, it is used to combine values corresponding to the same key; the default is to overwrite
the value from the earlier map with the later value. The result will be of the same type and
organization as the first set received, unless the iteration terminates without executing this
clause at all, in which case the result will be nil.
[Discussion: in the case of intersecting zero maps, there’s nothing reasonable this could return,
since there’s no such thing as a “full map”. (There is a full binary relation, but it’s not a
function.) So it may as well just return nil. For the same reason, there’s no point in it
accepting an initial value; if you want to change organizations, just convert the result.]