User Manual for the Series Macro Package by Richard C. Waters (MIT AI Memo 1082, 1989).

The benefits of programming in a functional style are well known. In particular, algorithms that are expressed as compositions of functions operating on series/vectors/streams of data elements are much easier to understand and modify than equivalent algorithms expressed as loops. Unfortunately, many programmers hesitate to use series expressions. In part, this is due to the fact that series expressions are typically implemented very inefficiently.

A Common Lisp macro package (called Series) has been implemented that can evaluate a wide class of series expressions very efficiently by transforming them into iterative loops. When using this class of series expressions, programmers can obtain the advantages of expressing computations as series expressions without incurring any run-time overhead.

There is an up-to-date copy of the Series package on Sourceforge.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.


Introducing Pipes, a lightweight stream fusion EDSL

Fusion is cool. It lets us write bulk data processing programs modularly, with each pass or computation separate from the rest, while retaining the efficiency of code that executes all the passes simultaneously rather than building large intermediate values. In the last couple years, most of the attention has been coming from the Haskell crowd (e.g. Data.List.Stream), but Lisper aren’t immune to that siren’s call. In the late 80’s, Richard Waters worked on SERIES, a Common Lisp package to transform “obviously synchronizable series expressions” into buffer-less loops. That package is still available, and even lightly maintained.

I believe that, while the goal is noble, the approach taken in SERIES is too magical; I’d argue that it’s even more true of stream fusion in GHC.

Only in simple cases.

I find the idea that it is easier (more readable and understandable) to use series expressions is only true in simple cases. If the unseen type transformations between pipe stages get too complex, it starts to get difficult to understand. Also if processing requires nested pipelines (like nested maps or folds) it gets pretty complicated quickly.

For more complex examples the stable types of mutable collections (where 'x' is an array of widgets for example) and the index parameters of loops (x[i][j] * y[j][i] for example) make algorithms considerably more readable and understandable.