[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: LOOP Macro a Winner



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...)