Overview
stateless-iterators
is a library which provides Lua-like stateless
iterators for Common Lisp. Stateless iterators work as follows:
- Suppose you have a function
next
which takes an argumentstate
and returns two values: a result of the current iteration step and a new state. Should iteration stopnext
returns a symbolstateless-iterators:stop
as the new state. - Iterator is a pair of the previously described function and an
initial state:
(stateless-iterator:iterator #'next initial-state)
. - A function
stateless-iterators:iterate-for-effects
takes an iterator and a functionfn
. It calls the iterating functionnext
with the initial state of the iterator. If iteration does not stop, the functionfn
is called with the first value returned bynext
as its only argument. Values returned byfn
are ignored. next
is called with the second value previously returned bynext
and the process repeates again until the next state is a symbolstateless-iterators:stop
.
Here is a simple iterator which infinitely counts from n
by 1:
(defun count-from/next (state)
(values state (1+ state)))
(defun count-from (n)
(stateles-iterators:iterator #'count-from/next n))
What's the difference with other iterator libraries (snakes being my favorite)? Iterators in this library do not contain mutable state inside themselves and so are reusable:
CL-USER> (defparameter *iter* (stateless-iterators:range 1 10))
*ITER*
CL-USER> (stateless-iterators:collect *iter*)
(1 2 3 4 5 6 7 8 9)
CL-USER> (stateless-iterators:collect *iter*)
(1 2 3 4 5 6 7 8 9)
CL-USER>
This allows to write iterators like product
where one of the iterators
must be restartable:
CL-USER> (let ((a (stateless-iterators:range 0 3)))
(stateless-iterators:collect
(stateless-iterators:product a a)))
((0 . 0)(0 . 1)(0 . 2)(1 . 0)(1 . 1)(1 . 2)(2 . 0)(2 . 1)(2 . 2))
CL-USER>
NB: All functions which are passed as arguments to functions of this
library are called in unspecified order, therefore they must not have any
side-effects. One exception to this is a function passed to
iterate-for-effects
. It is called right after a new value is obtained
from the iterator.