I was feeling energetic so I wrote a Lucid interpreter. I used Python and it turned out pretty well.

Lucid has been around for donkey’s years but for a long time there’s been no public implementation. Dataflow’s making a comeback and hopefully Lucid with it. I want it to be possible for interested people to run Lucid programs. Hence pyLucid.

There used to be an interpreter for pLucid, the dialect described in the 1985 “Lucid the Dataflow Language” book by me and my collaborator (and good friend), the (late) Ed Ashcroft. The book has, as an appendix, the pLucid manual. The interpreter was written by my former student (and also good friend) Tony Faustini and itself was a major rewrite of the first Lucid interpreter by Calvin Ostrum of (at the time) Waterloo.

The source for the pLucid interpreter is still around but it is no longer usable. C implementations are much less forgiving than they used to be and attempts to compile the source produce warnings or errors about every ten lines. Plus it is unwieldy and would be difficult to modify or extend. Time to start from scratch.

The first priority for pyLucid was to implement as much of pLucid as possible. Therefore I preserved the syntax and the domain of data objects based as they were on the syntax and data domain of POP2 (a long dead alternative to LISP, designed at Edinburgh for AI). In fact there are still good reasons for following POP2. It supports numbers, strings, and lists and also “words” (alphanumeric symbols). Also they had the brilliant idea of making the lexical conventions the same as the I/O conventions. This saved a lot of work on pyLucid.

(The programs in my blog posts are all pyLucid and can be run on the interpreter)

I made one major change from the old pLucid, namely the treatment of nested loops. The old pLucid (also called “Book Lucid”) had a nonstandard syntax and semantics for **where** clauses that allowed nested computations. The key was the **is_current** declaration that had the effect of freezing a value. Freezing was never very popular and many users avoided it completely.

In the Lucid book there is a section (chapter 7.4) that discusses “Llucid”, a more algebraic approach to nesting in which **current** is an operator like **first** or **next.** It declares the approach a failure because it requires two kinds of **where** clauses.

I decided this was in fact reasonable and so pyLucid indeed has two kinds of **where** clauses, **where** and **whereloop.** The **where** clause is completely standard in terms of syntax and semantics. The **whereloop** implements the algebraic nesting proposal, though if you don’t use **current** or other special nesting operators, it behaves like **where.** So users can define and experiment with special operators and so for example write nested loops where variables in enclosing loops are not necessarily frozen solid.

The pyLucid language goes beyond pLucid in other ways but these are extensions (ee.g.negative time) and don’t affect backwards compatibility.

The most important is the addition of a space parameter *s* which allows ‘streams’ that vary in both space and time. These two dimensional intensions can be thought of as (infinite) streams of infinite arrays – or as arrays of streams, the two dimensions being treated symmetrically. In terms of demand driven dataflow (the basis of the pyLucid implementation) the extra dimension is not a problem. On the other hand I don’t see how eager/data-driven dataflow can incorporate a space dimension.

Along with the extra dimension we have space analogs of **first,** **next, fby** etc, namely **init succ, sby** etc. Their use is well illustrated in the examples in the blog post on formal power series.

As it turns out pLucid had a number of undocumented features and one was (multiple) space dimensions. It had not only ‘arrays’ but arrays of arrays, arrays of double arrays etc. This required a hierarchy of array dimensions which complicated eduction. I decided to stick with a single space dimension for the time being.

Both pLucid and pyLucid supported end-of-data as described in a recent blog post.

And pyLucid supports negative time iteration, as described in yet another post.

Finally pyLucid supports a new idea, namely *parameters* to control output. Output in pyLucid is currently pretty basic, designed for a terminal screen. Data being output is normally two dimensional, as is the terminal screen, and pyLucid simply matches up the dimensions. Space is displayed (varies) horizontally, and time vertically. So the first line is *t*=0 and *s*=0,1,2,…; the second line is *t*=1 and *s*=0,1,2,…; then *t*=2 and *s*=0,1,2,…; and so on.

In pyLucid even the space dimension is infinite so we have a problem. We can display indefinitely many lines but not indefinitely many columns easily. (Hmm we could scroll in both dimensions, I’ll have to think about this).

Anyway in the simplest case we want only fixed numbers of columns and rows and pyLucid parameters allow you to do this. If you only want 2 columns and 10 rows you add definitions for the parameters (pseudo-variables) *columns* and *rows*:

columns = 2;

rows = 10;

In addition if you want only 6 decimals you add

numformat = ‘%8.6f’;

(using Python’s output formatting convention) and as a bonus the columns line up. These parameters can have any valid defining expressions on the right hand side, you could even, for example, have *columns* vary in time. I have other plans for parameters.

Compiling and interpreting pyLucid will be covered in a followup post published at the same time.