Concerning stephen's item (2).
The stricter set of rules was laid out by Richard C. Waters
in Optimization of Series Expressions: Part I: User's Manual for the Series Macro Package, page 46 (document page 48). See reference Waters(1989a).
The paper's language is a bit different than contemporary (2023) language.
`map()` is called `map-fn`.
`reduce()` a.k.a. `fold` seems to be `collect-fn`, although `collecting-fn`
also seems interesting.
sorting, uniqueness and permutation seem to be covered by `producing`.
Just think of McIlroy's famous pipeline in response to Donald Knuth's trie implementation[mcilroy-source]:
tr -cs A-Za-z '\n' |
tr A-Z a-z |
sort |
uniq -c |
sort -rn |
sed ${1}q
As far as pipeline or stream processing diagrams are concerned, the diagram on page 13 (document page 15) of Waters(1989a) may also be worth a closer look.
What the SERIES compiler does is pipeline the loops. Think of a UNIX shell
pipeline. Think of streaming results. Waters calls this pre-order processing.
This also seems to be where Rich Hickey got the term "transducer" from.
In short it means dropping unnecessary intermediate list or array allocations.
Shameless self-plug: Eliminated unnecessary allocations in my JavaScript code
by adding support for SERIES to the PARENSCRIPT Common Lisp to JavaScript
compiler. The trick was (1) to define (series-expand ...) on series expressions so that they can be passed into (parenscript:ps ...) and (2) the parenscript
compiler was missing (tagbody ... (go ...) ...) support. The latter is
surprisingly tricky to implement. See dapperdrake(2023). Apologies for
the less than perfect blog post. Got busy actually using this tool.
Suddenly stream processing is easy, and maintainable.
When adding a Hylang-style threading macro (-> ...) you get UNIX style
pipelines without unnecessary allocations. It looks similar to this:
(-> (it :let*-symbol series::let)
(scan-file in-path-name #'read)
(map-fn T #'some-function it)
(collect 'list it))
Sadly, the SERIES compiler available on quicklisp right now is a
bit arcane to use. It seems like it may have been more user friendly
if it would have been integrated into the ANSI Common Lisp 1995 standard
so that is has access to compiler internals. The trick seems to be to
use macros instead of (series::defun ...) and use (series::let ...) instead of (cl:let ...). Note, that the two crucial symbols 'defun and 'let
are
not exported by SERIES. So using the package is insufficient
and pipelining fails without a decent warning.
Am chewing on the SERIES source code. It is available on sourceforge. [series-source].
If anybody is interested in porting it, then please reach out.
It seems to be of similar importance as Google's V8 relooper algorithm [relooper-reference].
Waters(1989b), page 27 (document page 29) even demonstrates an implementation for Pascal. So it is possible.
References:
dapperdrake(2023): Faster Loops in JavaScript
https://dapperdrake.neocities.org/faster-loops-javascript
Waters(1989a)
document page 48, paper page 46
https://dspace.mit.edu/bitstream/handle/1721.1/6035/AIM-1082...
Waters(1989b)
document page 29, paper page 27
https://dspace.mit.edu/bitstream/handle/1721.1/6031/AIM-1083...
[relooper-reference]
http://troubles.md/why-do-we-need-the-relooper-algorithm-aga...
[series-source]
https://series.sourceforge.net/
[mcilroy-source]
https://franklinchen.com/blog/2011/12/08/revisiting-knuth-an...