--- a/DOCUMENTATION.markdown Mon May 24 01:18:26 2021 -0400
+++ b/DOCUMENTATION.markdown Mon Jul 12 22:03:01 2021 -0400
@@ -455,6 +455,28 @@
Perform `body` `n` times.
+### `DO-VECTOR` (macro)
+
+ (DO-VECTOR (VAR-OR-VARS VECTOR)
+ &BODY
+ BODY)
+
+Iterate over `vector`, performing `body` with `var-or-vars` bound.
+
+ `var-or-vars` can be one of the following:
+
+ * `value-symbol`
+ * `(value-symbol)`
+ * `(index-symbol value-symbol)`
+
+ Successive elements of `vector` will be bound to `value-symbol` while `body`
+ is executed. If `index-symbol` is given, the current index will be bound to
+ it.
+
+ Returns `nil`.
+
+
+
### `GATHERING` (macro)
(GATHERING
@@ -1112,9 +1134,11 @@
Graph `data` with gnuplot using `commands`.
- `data` must be an alist of `(identifier . data)` pairs. `identifier` must be
- a string of the form `$foo`. `data` must be a sequence of sequences of data
- or a 2D array of data.
+ `data` must be an alist of `(identifier . data)` pairs.
+
+ Each `identifier` must be a string of the form `$foo`. Each `data` must be
+ one of the following: a sequence of sequences of data points, an alist of data
+ points, or a 2D array of data points.
`commands` must be a string or a sequence of strings.
@@ -1138,7 +1162,8 @@
`identifier` must be a string of the form `$foo`.
- `data` must be a sequence of sequences of data or a 2D array of data.
+ `data` must be one of the following: a sequence of sequences of data points,
+ an alist of data points, or a 2D array of data points.
Must be called from inside `with-gnuplot`.
@@ -1154,9 +1179,21 @@
+### `PLOT` (function)
+
+ (PLOT DATA &KEY (STYLE :LINESPOINTS) (FILE plot.pdf))
+
+Plot `data` with gnuplot.
+
+ Convenience wrapper around the gnuplot functions. This is only intended for
+ REPL-driven experimentation — if you want any customization you should use the
+ gnuplot interface instead.
+
+
+
### `WITH-GNUPLOT` (macro)
- (WITH-GNUPLOT
+ (WITH-GNUPLOT OPTIONS
&BODY
BODY)
@@ -1442,6 +1479,35 @@
Custom `iterate` drivers and clauses.
+### `IF-FIRST-ITERATION` (macro)
+
+ (IF-FIRST-ITERATION THEN ELSE)
+
+Evaluate `then` if this clause is executed on the first iteration, otherwise `else`.
+
+ This is similar to from iterate's built-in `if-first-time`, but slightly different:
+
+ * `if-first-time` evaluates `then` the first time the clause is evaluated,
+ even if that happens on a subsequent iteration.
+ * `if-first-iteration` evaluates `then` only if the clause is evaluated on
+ the first iteration.
+
+ Example:
+
+ (iterate
+ (for i :from 1 :to 4)
+ (collect (cons i (when (evenp i)
+ (list
+ (if-first-time :first-time :later-time)
+ (if-first-iteration :first-iter :later-iter))))))
+ ; =>
+ ; ((1)
+ ; (2 :FIRST-TIME :LATER-ITER)
+ ; (3)
+ ; (4 :LATER-TIME :LATER-ITER))
+
+ in that it will only evaluate `then` on the first iteration of the loop,
+
### `MACROEXPAND-ITERATE` (function)
(MACROEXPAND-ITERATE CLAUSE)
@@ -1469,6 +1535,30 @@
+### `UNLESS-FIRST-ITERATION` (macro)
+
+ (UNLESS-FIRST-ITERATION EXPR)
+
+Sugar for `(if-first-iteration nil expr)`.
+
+### `UNLESS-FIRST-TIME` (macro)
+
+ (UNLESS-FIRST-TIME EXPR)
+
+Sugar for `(if-first-time nil expr)`.
+
+### `WHEN-FIRST-ITERATION` (macro)
+
+ (WHEN-FIRST-ITERATION EXPR)
+
+Sugar for `(if-first-iteration expr nil)`.
+
+### `WHEN-FIRST-TIME` (macro)
+
+ (WHEN-FIRST-TIME EXPR)
+
+Sugar for `(if-first-time expr nil)`.
+
## Package `LOSH.LISTS`
Utilities for operating on lists.
--- a/src/iterate.lisp Mon May 24 01:18:26 2021 -0400
+++ b/src/iterate.lisp Mon Jul 12 22:03:01 2021 -0400
@@ -1061,3 +1061,54 @@
(aref ,reg-start% ,i)
(aref ,reg-end% ,i))))))))))))))))
+
+(defmacro WHEN-FIRST-TIME (expr)
+ "Sugar for `(if-first-time expr nil)`."
+ `(if-first-time ,expr nil))
+
+(defmacro UNLESS-FIRST-TIME (expr)
+ "Sugar for `(if-first-time nil expr)`."
+ `(if-first-time nil ,expr))
+
+
+(defmacro IF-FIRST-ITERATION (then else)
+ "Evaluate `then` if this clause is executed on the first iteration, otherwise `else`.
+
+ This is similar to from iterate's built-in `if-first-time`, but slightly different:
+
+ * `if-first-time` evaluates `then` the first time the clause is evaluated,
+ even if that happens on a subsequent iteration.
+ * `if-first-iteration` evaluates `then` only if the clause is evaluated on
+ the first iteration.
+
+ Example:
+
+ (iterate
+ (for i :from 1 :to 4)
+ (collect (cons i (when (evenp i)
+ (list
+ (if-first-time :first-time :later-time)
+ (if-first-iteration :first-iter :later-iter))))))
+ ; =>
+ ; ((1)
+ ; (2 :FIRST-TIME :LATER-ITER)
+ ; (3)
+ ; (4 :LATER-TIME :LATER-ITER))
+
+ in that it will only evaluate `then` on the first iteration of the loop, "
+ (with-gensyms (first-iteration)
+ `(progn
+ (with ,first-iteration = t)
+ (after-each (setf ,first-iteration nil))
+ (if ,first-iteration
+ ,then
+ ,else))))
+
+(defmacro WHEN-FIRST-ITERATION (expr)
+ "Sugar for `(if-first-iteration expr nil)`."
+ `(if-first-iteration ,expr nil))
+
+(defmacro UNLESS-FIRST-ITERATION (expr)
+ "Sugar for `(if-first-iteration nil expr)`."
+ `(if-first-iteration nil ,expr))
+
--- a/src/package.lisp Mon May 24 01:18:26 2021 -0400
+++ b/src/package.lisp Mon Jul 12 22:03:01 2021 -0400
@@ -308,13 +308,14 @@
:collect-frequencies
:collect-hash
:collect-set
+ :concatenating
:cycling
- :concatenating
:end
:every-nth
:finding-all
:finding-first
:for-nested
+ :if-first-iteration
:in-array
:in-hashset
:in-lists
@@ -341,6 +342,10 @@
:test
:then
:timing
+ :unless-first-iteration
+ :unless-first-time
+ :when-first-iteration
+ :when-first-time
:within-radius
))