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

Re: loop macro



    Date: Wed, 5 Feb 86 10:49 EST
    From: Daniel L. Weinreb <DLW@SCRC-QUABBIN.ARPA>

    We could add grouping without going so far as to force all clauses
    to the front.

    (loop (for a from 4 below 7)
          (for b from 7)
          (do ..body..)
          (until ..pred..))

    I think this might be an improvement.  One problem is that we were
    hoping to get rid of the "do" keyword entirely (Moon agrees with this),
    but with this change, it's harder to see how to accomplish that.

Actually, people have been promised that if they don't use atoms in
their loop, it loops forever, though possibly no one has been brave
enough to use this behavior.  Still, I have to agree that this stuff
looks too much like function calls, and even if "FOR" and "UNTIL" are
somehow implemented as macros, it's not the way I think of it.

These problems and DO-removal are both solved by using alternating
keywords and arguments.  In the following, I don't use colons for the
LOOP keywords, since they don't follow the CL keyword standard anyway.

(DEFUN count-change (changepurse &OPTIONAL handfull)
   (LOOP				;(LOOP
      MEMBERS (coin changepurse)	;  FOR coin IN changepurse
      COUNT (howmany :END handfull)     ;  AS count = 0 TO handfull
      (jingle)				;  DO (jingle)
      (IF (soup coin)			;  IF (soup coin)
          (COLLECT (coin :INTO sou-list);     COLLECT coin INTO sou-list
        (SUM (coin-value coin)))	;     ELSE SUM (coin-value coin)
      (IF (= howmany handfull)		;  IF (= howmany handfull)
          (RETURN "Too Many"))		;     RETURN "Too Many"
      FINALLY (drop-coins sou-list)))   ;  FINALLY (drop-coins sou-list))

Each keyword takes exactly one argument, which is usually a standard CL
argument list (though possibly a single argument could be rendered as
an atom).  If not preceded by a keyword, the form is just evaluated.

    I am particularly grossed out by the idea of having a "dangling ELSE"
    in Lisp.

This is fixed here, since my IF uses Common Lisp syntax.  On my braver
days, though, I would rather use

	(IF (mantrap phrase)
	    (chant phrase)
	    (chant phrase)
	    (chant phrase)
	    :ELSE ((contemplate phrase)
	           (get-new-mantra)))

but that would break everyone's habits.

    The main reason for the conditionals is so that COLLECT clauses can be
    executed conditionally. (I don't know for sure whether there are other
    reasons for the conditionals.)  The usual proposed solution is to make
    COLLECT a regular Lisp macro... a separate facility completely
    orthogonal to LOOP.... After all, suppose you want to write a program
    that does a double recursion down a binary tree, and collects something
    as it goes?

I used this form above, but there are problems.  Consider the very
useful

    (LOOP MEMBERS (x elts) SUM x)
vs. (LOOP MEMBERS (x elts) COLLECT (- x)).

When elts is empty, the first should return 0 and the second NIL.  Also,
LOOP needs some preamble code for every variable you COLLECT :INTO.  I
guess we need declarations of the variables you are going to use for
SUM and COLLECT.
    TOTAL (coin-value)
    ACCUMULATE (:RETURN-VALUE)
Where :RETURN-VALUE refers to SUM or COLLECT calls that operate on the
value to be returned by LOOP.  It's unfortunate that this hair has to
be added.  I think ACCUMULATE :UNNAMED should be the default unless
TOTAL :UNNAMED appears.  Something like this is also needed in the
standalone SUM/COLLECT you propose.

Dan Hoey