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-iteration
nil
inext
(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-ended
get-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-iterator
defined 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-object
A 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-iterator
stream
The stream that the file-iterator is backed by.by-line
Whether or not we are reading by lines. Only applies to character streams.read-fun
The 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)