[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: LOOP Macro a Winner
- To: gsb at MIT-ML, moon at MIT-MC
- Subject: Re: LOOP Macro a Winner
- From: Guy.Steele at CMU-10A
- Date: Mon ,17 Nov 80 20:38:00 EDT
- Cc: lisp-forum at MIT-MC
I haven't much liked LOOP macros in the past, but I think I endorse
this one (for whatever that is worth). A few points:
(a) There is a "dangling AND" problem, similar to the "dangling ELSE"
problem with IF-THEN-ELSE. Suppose I write:
(LOOP FOR I IN LIST-OF-INTEGERS
WHEN (ODDP I)
DO (FORMAT T "~%~D is odd" I)
AND WHEN (ZEROP (REMAINDER I 3))
DO (FORMAT T " and divisible by 3")
AND (FORMAT T "."))
That is, I want to print a message if I is odd, and add something
to the message if also divisible by 3. The message should always
end in a period.
However, the above evidently gets parsed as:
(LOOP FOR I IN LIST-OF-INTEGERS
WHEN (ODDP I)
DO (FORMAT T "~%~D is odd" I)
AND WHEN (ZEROP (REMAINDER I 3))
DO (FORMAT T " and divisible by 3")
AND (FORMAT T "."))
That is, it resolves the ambiguity the same way dangling ELSEs
usually are: the AND is attached to the *innermost* eligible
construct.
Unfortunately, LOOP doesn't provide BEGIN-END blocks or FI for
resolving the other way.
Would it be hard to let a FI or NEHW or SSELNU or ENDIF or something
terminate the innermost conditional? Then I could write:
(LOOP FOR I IN LIST-OF-INTEGERS
WHEN (ODDP I)
DO (FORMAT T "~%~D is odd" I)
AND WHEN (ZEROP (REMAINDER I 3))
DO (FORMAT T " and divisible by 3")
NEHW
AND (FORMAT T "."))
and expect it to work as desired.
(Actually, would it be hard to add an ELSE as well?
(LOOP ... IF x ... ELSE ...) would be about the same as
(LOOP ... IF x ... UNLESS x ...) except for not evaluating x twice.
You could allow THEN to be a gratuitous buzzword. But I won't
be disappointed if you turn this down: that way lies madness
(or at least PL/I).)
(b) I propose that a form NAMED be added for naming the loop for use
with RETURN-FROM:
(LOOP NAMED SUE
FOR HORRIBLE-THING IN CAVE
... (LOOP ... (RETURN-FROM SUE ...) ...) ...)
(c) How about an easy way to declare new kinds of collecting LOOP
forms? (That way I don't have to bug you to add my favorites.)
Examples:
(DEFINE-LOOP-COLLECTOR (NRECONC NRECONCING) NRECONC () T)
(DEFINE-LOOP-COLLECTOR (MULTIPLY MULTIPLYING) TIMES 1 T)
(DEFINE-LOOP-COLLECTOR (MAXIMIZE MAXIMIZING MAXING) MAX 0 ())
(DEFINE-LOOP-COLLECTOR (COLLECT-UNIQUE COLLECTING-UNIQUE)
CONS-UNIQUE () T)
where (DEFUN CONS-UNIQUE (X Y) (IF (MEMQ X Y) Y (CONS X Y)))
Here we have the general form
(DEFINE-LOOP-COLLECTOR <keyword-names> <combining-function>
<init-value> <combine-first?>)
where <keyword-names> and <combining-function> are obvious,
<init-value> is the value if zero things are collected, and
<combine-first?> is a truth value: non-() means the value after collecting
one thing is the result of applying <combining-function> to the thing
and the <init-value>, while () means the value after collecting
just one thing is the thing itself.
Maybe this isn't general enough, but you get the idea of what I want.
CONSING would be like COLLECTING but would produce a reversed list.
UNIONING and INTERSECTING would also be useful. (I realize that
one can get those by writing some parentheses, but...)