Programming Language for Old Timers

by David A. Moon
February 2006 .. September 2008

Comments and criticisms to dave underscore moon atsign alum dot mit dot edu.

List Comprehensions

If you like list comprehensions they are easy to implement for yourself. Here is an example definition that uses essentially the same syntax as Python:

```defmacro \{ ?value { for ?:variable in ?list | if ?test }+ \} =>
;; wrap up nested fors and ifs
def wrapper := ``
for v in variable, l in list, t in test
if l
wrapper := `?wrapper for ?v in ?l`
else
wrapper := `?wrapper if ?t`
;; expansion does the iterations, accumulating results in a stack
`block
def result = stack()
?wrapper result.push := ?value
result.bottom-up`
```

Now you can write things like:

```{ 2 * x for x in 0 .. 100 if x ^ 2 > 3 }

{ i for i in 0 .. 10 }

{ i for i in 0 .. 10 if i mod 2 = 0 }

;; nested iteration example
def nums = 1 .. 4
def fruits = #["Apples", "Peaches", "Pears", "Bananas"]
{ list(i, f) for i in nums for f in fruits }
{ list(i, f) for i in nums for f in fruits if f[0] = 'P' }
{ list(i, f) for i in nums for f in fruits if f[0] = 'P' if i mod 2 = 1 }
```

You can also define a syntax closer to standard mathematical notation allowing you to write, for example:

```{ list(i, f) | i in nums, f in fruits, f[0] = 'P', i mod 2 = 1 }
```

The definition of this list comprehension syntax is

```defmacro \{ ?value \| { ?test [ in ?list ] & , ^^ }+ \} =>
;; wrap up nested fors and ifs
def wrapper := ``
for l in list, t in test
if l
if not t is name
error(#"invalid variable name ?t in list comprehension")
wrapper := `?wrapper for ?t in ?l`
else
wrapper := `?wrapper if ?t`
;; expansion does the iterations, accumulating results in a stack
`block
def result = stack()
?wrapper result.push := ?value
result.bottom-up`
```

Note the trick of parsing an iteration variable as an expression and then reporting an error if the expression is not just a name. This makes it possible to parse the syntax with only one-token lookahead, i.e. LL(1).

For this use of | to work, you must not import the standard | operator from the PLOT module into your module. Or you could change the list comprehension syntax to use : instead of |.

Alternatively you could give value the syntactic type expression-no-vbar and define parse-expression-no-vbar as a modified copy of parse-expression which does not recognize | as an infix operator. Any use of that operator would have to be enclosed in parentheses.