Liter is a collection of tools to work with basic iterators.
An iterator in Liter is just a function (usually a closure) which returns the next value in the iterable, and signals a ITERATION-ENDED condition if there are no more values. It should follow the following rules:
- An iterator MAY be called with optional, keyword, or rest arguments, but MUST function correctly if called with no arguments.
- If an iterator has completed, it SHOULD signal an ITERATION-ENDED condition, typically using END-ITERATION.
- Once an iterator signals an ITERATION-ENDED condition, it SHOULD signal an ITERATION-ENDED condition on each future call, unless something changes the state of the iterator so that it can continue iterating.
- Client code SHOULD handle any ITERATION-ENDED condition, or use a function or macro that does (such as the iterate drivers, DO-ITERATOR, etc).
- Additional return values may be ignored by the caller of an iterator.
- By convention, key-value pairs SHOULD be represented as a cons pair. (as in alists)
- An iterator MAY be infinite, but not all liter functions can be safely used with such iterators. Functions such as ITAKE can be used to convert an infinite iterator to a finite one.
An iterable is any object for which there is a method defined for GET-ITERATOR. Most liter function accept an iterable, and will get an iterator using GET-ITERATOR. There is a GET-ITERATOR method defined for iterators that is equivalent to the identity function, so iterators can be passed to these functions.
Basic Functionality
get-iterator(iterable)end-iterationnilinext(iterator &rest args)Return the next value of an iterator and whether or not an actual value was retrieved as values.
Any additional arguments are passed through to the iterator function.
iteration-endedget-iterator((f function))get-iterator((l list))get-iterator((s vector))get-iterator((a array))get-iterator((h hash-table))Iterate over elements of a hash-table. Returns a cons of the key and value.
Since a clousre over a the form from a HASH-TABLE-ITERATOR is undefiend, at the time of creation a list of keys is created and the iterator closes over that.
If you know of a better way of doing this, please let me know.
get-iterator((s stream))make-hash-key-iterator(h)make-hash-value-iterator(h)make-character-stream-iterator(stream)make-byte-stream-iterator(stream)make-line-iterator(stream)do-iterator((var iterator &optional return) &body body)do-iterable((var iterable &optional return) &body body)iterator-list(iterator)Liter also provides two iterate drivers:
FOR var IN-ITERATOR it- Iterates through the items in an iterator
it FOR var IN-ITERABLE it- A more generic driver clause that will iterate over anything with
get-iteratordefined on it.
Generators
The Following API is provided by theliter/generate package (inluded in the liter
package). These functions can be used to create iterators that abstract some sort of sequence.icounter(&key (from 0) (by 1) (to 0 stop-p))Create an iterator that just counts up from FROM by amount BY forever. The returned iterator takes an optional argument which resets the counter if true.
If a TO parameter is provided, then the counter will stop when the value returned would equal the TO parameter. Note that if using a BY parameter it is possible to step over the TO end-point, but a >= comparison is undesirable because it wouldn't work for a negative step.
irepeat(v &optional (n -1))Create an iterator that returns the value V N times. If N is negative (the default) iterate forever.
Note that CONSTANTLY is equivalent to IREPEAT with a negative N, and in fact there is a compiler macro that compiles IREPEAT as CONSTANTLY in that case.
singleton-iterator(element)Create an iterator that returns element on the first iteration, and ends on the second.
Equivalent to `(irepeat element 1)`.
icycle(iterable)icycle*(&rest args)make-iterator(&body body)Create an iterator that executes BODY each time.
Basically a simple wrapper for LAMBDA. Iteration can be ended by calling END-ITERATION.
make-state-iterator.make-state-iterator*(initial-state (&rest lambda-list) &body body)Tools
The following API provides additional tools to perform operations on iterators and iterables.itransform(iterable map-fun)Return an iterator that iterates over transformed values of an iterable.
ITERABLE is on object for which GET-ITERATOR is defined. MAP-FUN is a function which is called with each value returned by the iterator and returns the value that the new iterator should return.
ifilter(iterable predicate)ifold(iterable op &optional initial)iaccumulate(iterable &optional (op (quote +)))Return an iterator that accumulates the results of appling OP to the previous result and the current item.
IACCUMULATE is like IFOLD that keeps track of intermediary results.
ichain(first &rest rest)izip(&rest iterables)Zip iterables together.
This returns an iterator that returns a list of the results of getting the next value from each iterable. The iterator ends when the shortest of the iterables ends.
izip-longest(missing-value &rest iterables)izip-with-index(iterable)Zip an iterable with an index.
Each element of the new iterator is a list of the index (starting with 0) and the next element of ITERABLE.
itee(iterable &optional (n 2))itake(iterable n)itake-while(iterable pred)idrop(iterable n)idrop-while(iterable pred)ITER-OBJECT
iter-objectA class to represent an iterator object.
If closer-mop is enabled, it is a funcallable object that calls ITER-OBJECT-NEXT when called. Otherwise GET-ITERATOR returns a function that calls ITER-OBJECT-NEXT.
Subclasses should use a metaclass of FUNCALLABLE-STANDARD-CLASS if mop is available.
iter-object-next(iter-object &rest args)iter-object-prev(iter-object &rest args)Get the previous object in the iter-object iterator.
This is optional for iter-object implementations.
iter-object-end-p(iter-ojbect)File iterator
file-iteratorstreamThe stream that the file-iterator is backed by.by-lineWhether or not we are reading by lines. Only applies to character streams.read-funThe function to use to read from the stream.
make-file-iterator(filename &key by-line (element-type (quote character)) (if-does-not-exist error) (external-format default))Create a FILE-ITERATOR using the same arguments as OPEN. In fact this is basically like OPEN, but returns a FILE-ITERATOR instead of a stream.
If BY-LINE is true, and the ELEMENT-TYPE is a subtype of CHARACTER, then the iterator will return whole lines at a time instead of individual characters.
with-file-iterator((var filename &key by-line (element-type (quote (quote character))) (if-does-not-exist error) (external-format default)) &body body)