Sebastian Egner wrote in his mail message of 1996/03/23
being an enthusiastic GAP user and programmer, I have collected two
suggestions on improving the GAP language itself. Although I appreciate
the idea of `lean' languages, as for example GAP is, it seems to me that
GAP might benefit from these additions. Especially ZF-comprehensions
turned out to be so useful in other languages I used before (Gofer,
Haskell) that I would be very glad to have it in GAP, too. In case these
ideas fit the general design considerations and development strategy of
the GAP-project I would like to do actual implementation work on it.
Thank you very much for your suggestions and your offer to help us
implement them.
Iterators will be supported in the next version of GAP. The names
and semantics will be very similar to the ones you suggest.
I also like list comprehensions very much. They are especially useful
for interactive use (but I don't use them often in my programs).
However comprehensions with the syntax you describe require major changes
to the parser. In particular they require unbounded lookahead (whether a
variable in the expression refers to an outer variable or a loop variable
cannot be decided before the entire comprehension has been parsed).
I think that a small change to 'List', 'Set' are almost as good. Allow
me to describe them (using 'List' as example).
'List' would take 2 or more arguments. Every argument but the last can be
1) a list or a domain (to introduces a new loop variable),
2) a function returning a list or a domain (to have the elements to loop
over depend on the values of the outer loop variables),
3) a function returning 'true' or 'false' (to filter).
The last argument must be function, which is applied to the values of
the loop variables and whose results are collected.
Understanding this function is probably much easier by examples than from
a formal definition. So here is how your first example
[ x^2 | for x in [100, 99 .. 1], IsPrime(x) ] # comprehension
can be expressed using this extended 'List'
List( [100, 99 .. 1], x -> IsPrime(x), x -> x^2 ) # GAP
or since 'x -> IsPrime(x)' is equivalent to 'IsPrime'
List( [100, 99 .. 1], IsPrime, x -> x^2 ) # GAP
(which is even shorted than the comprehension).
And your second example
{ [n, r] | for n in [1..10], for r in PrimeResidues(n) } # comprehension
can be written as follows
Set( [1..10], n->PrimeResidues(n), function(n,r) return [n,r] end ) # GAP
Of course it would be nice to have a short notation for functions of more
than one argument, so that the latter can be written as
Set( [1..10], n -> PrimeResidues(n), (n,r) -> [n,r] )
Using the function 'ListArgs', which simply returns the list of its
arguments (i.e., 'ListArgs := function ( args ) return args; end;'),
we can express the last examples as follows
Set( [1..10], PrimeResidues, ListArgs ) # GAP
(which is pretty short, but not so easy to read).
One nice thing is that it is easy to generalize 'Sum' and 'Product'
likewise. With comprehensions you would either have to create the entire
list and sum afterwards or come up with yet another syntactic extension.
Kindly, Martin.
-- .- .-. - .. -. .-.. --- ...- . ... .- -. -. .. -.- .- Martin Sch"onert, Martin.Schoenert@Math.RWTH-Aachen.DE, +49 241 804551 Lehrstuhl D f"ur Mathematik, Templergraben 64, RWTH, 52056 Aachen, Germany