7.6 Iterate

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:

Iterate clause: for var in-set set

Yields the elements of set.

Iterate clause: for var in-bag bag

Yields the elements of bag. Elements with multiplicities greater than 1 will be repeated that many times.

Iterate clause: for (var count) in-bag bag

Yields the pairs of bag, binding var to each element and count to its multiplicity.

Iterate clause: for (key value) in-map map

Yields the pairs of map, binding key to each key and value to its value.

Iterate clause: for var in-seq seq  &optional from from upfrom upfrom downfrom downfrom to to downto downto above above below below by step with-index with-index

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.

Iterate clause: for var in-collection coll

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:

Iterate accumulator: collect-set expr  &optional initial-value init-val into var-spec

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.

Iterate accumulator: collect-bag expr  &optional initial-value init-val into var-spec

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.

Iterate accumulator: collect-bag expr count count-expr  &optional initial-value init-val into var-spec

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.

Iterate accumulator: collect-seq expr  &optional into var-spec

Collects values into a seq.

Iterate accumulator: collect-map (key value)  &optional initial-value init-val into var-spec

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.

Iterate accumulator: collect-map-to-sets (key value)  &optional initial-value init-val into var-spec

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).

Iterate accumulator: unioning expr  &optional initial-value init-val into var-spec

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.)

Iterate accumulator: intersecting expr  &optional initial-value init-val into var-spec

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.

Iterate accumulator: concating expr  &optional into var-spec

Concatenates successive seqs into a result seq.

Iterate accumulator: map-unioning expr  &optional combining-with val-fn initial-value init-val into var-spec

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.

Iterate accumulator: map-intersecting expr  &optional combining-with val-fn into var-spec

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.]