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.


Previous page   Table of Contents   Next page


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.


Previous page   Table of Contents   Next page