Binary comprehensions

Richard A. O'Keefe ok@REDACTED
Tue Aug 17 03:38:47 CEST 2004

Luke Gorrie <luke@REDACTED> wrote:
	Speaking of comprehensions, does anyone else think that the way
	multiple generators in a list comprehension works is weird?

I don't think it is weird for an instant.
I _do_ think that more expressiveness would be good.

	I think this behaviour would be better:
	  [{X,Y} || X <- [1,2,3], Y <- [a,b,c]]    => [{1,a},{2,b},{3,c}]
	i.e. to walk over the lists in parallel instead of trying all the
	combinations. I'm always writing code that walks down two lists in
	parallel and very rarely wanting all the combinations.
In old Interlisp terms, you want

    (FOR X IN '(1 2 3) AS Y IN '(a b c) COLLECT (TUPLE X Y))

The Haskell approach is of course

    [(x,y) | (x,y) <- zip [1,2,3] [A,B,C]]

which always makes me cringe a bit and hope to goodness that the compiler
will get rid of the call to zip.

Clean does what I think is the right thing.  It offers nested generators,
as in Haskell and Erland, *and* it offers parallel generators, all within
the same construct.

>From the Clean 1.3 manual (because I don't happen to have a 2.x manual

(1) ArrayComprehension = '{' GraphExpr '\\' Qualifier-list '}'
(2) ListComprehension  = '[' GraphExpr '\\' Qualifier-list ']'
(3) Qualifier          = Generators ['|' Guard]
(4) Generators         = Generator {'&' Generator}
(5) Generator          = Selector '<-' ListEpxr
                       | Selector '<-:' ArrayExpr

-- rule numbers added by me.

(1) and (2): Clean offers array (= Erlang tuple) comprehension as well as
list = (Erlang list) comprehension.  This does not involve creation of an
intermediate list.  (Mind you, the way Clean 1.3 did this was a bit
simplistic; it didn't work well with guards.)

(3) In Clean, as in Haskell, guards are expressions returning Bool.

(4) A qualifier-list is a sequence of qualifiers joined by commas.
This is *nested* generation, just like Haskell and clean.
But two or more generators can be joined by ampersands, and this is
*parallel* generation, which is what Luke Gorrie wants.

(5) Not only does Clean let you build a tuple with a comprehension,
without any intermediate list, it lets you iterate over a tuple without
any intermediate list either.  The two obviously connect:  if you do
    { x + 1 \\ x <-: arr }
then the size of the result can be calculated at once from the size of 'arr'.

	I'm not suggesting it be changed (of course). I just think it's funny
	that list comprehensions turn up in lots of programminig languages and
	I hardly ever see someone use more than one generator at a time.
	Syntactic sugar should optimize for the most common cases, right?
I _am_ suggesting that Erlang list comprehension syntax could be
_extended_ to include parallel generation, without breaking old code,
and that this would be worth doing.

Much depends on one's coding style and whether one is using a strict or
a lazy language.  Nested generation is far more common in Haskell than it
is in Erlang.

More information about the erlang-questions mailing list