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

RE: COND/DO consistency



I had proposed the following:

>   | (DO ((<variable> <init> <step>)
>   |      ...)
>   |     (<test> <expression>...)
>   |   <command>...)
>   |
>   | If the <test> evaluates to a true value, then the value of the last
>   | <expression> is returned as the result of the DO. If no <expression>s
>   | are present, then the value of the DO expression is unspecified.
>   
>   I propose that this last line read "then the value of the <test> is
>   returned as the value of the DO expression." for consistency with the
>   way test clauses are handled in COND.
>   
>   Consequently, I propose that the rewrite rule for DO in section 7.3
>   be changed to:
>   
>   | (DO ((<variable_1> <init_1> <step_1>)
>   |      ...)
>   |     (<test> <expression>...)  ;; NB: <sequence> changed to <expr>...
>   |   <command_1>...)
>   |
>   | = (LETREC ((<loop>
>   |              (LAMBDA (<variable_1>...)
>   |                 (COND (<test> <expression>...)        ;; NB: COND
>   |                       (ELSE <command_1>               ;;  not IF
>   |                             ...                       ;;
>   |                             (<loop> <step_1>...)))))) ;;
>   |       (<loop> <init_1>...))

Morry countered by generalizing this to have potentially many <test> clauses:

>   | (DO ((<variable_1> <init_1> <step_1>)
>   |      ...)
>   |     ((<test> <expression>...)  ;; NB: <sequence> changed to <expr>...
>   |      ...)
>   |   <command_1>...)

This is a more substantial change and, as Morry noted, it is not compatible with
the current DO syntax.  I would like to add that I have never had occasion to
malign the language for not providing a more general exit <test> structure.  To
point, I have adopted the following idiom:

(DEFINE call-with-nonlocal-exit call-with-current-continuation)

(DEFINE (first-such-that test-pred lst)
  (call-with-nonlocal-exit
    (LAMBDA (exit)
      (DO ((to-do  lst  (CDR to-do)))
          ((NULL? to-do) *THE-CANONICAL-FAILURE-OBJECT*)
        (LET ((next (CAR to-do)))
          (COND ((test-pred next) (exit next))
                ((something-interesting? next) (exit (mumble next)))
		...
		))))))

I find this not excessively verbose and I actually enjoy the distinction between
the "normal" loop-variable-exhausted exit condition to the "exceptional"
short-cut-situation exit condition.  I have generalized this into a
SHORT-CURCUIT-ACCUMULATE idiom which I use fairly often.

My point is that I would not like my initial painless proposal to be
overshadowed or superceeded by a more controversial counter-proposal.  I really
have had occasion to want to return the result of the non-FALSE test.  For
example, when I exit with the first element of a list which has a frame in a
possibly lengthy association list, I don't cherish the thought of probing for
the frame twice and I don't relish named-LET or LETREC as an alternative since
this obscures the DO-ish nature of the iteration.  I prefer DO when doing DO-ish
doodles, but when faced with multiple exit conditions, I prefer the
nonlocal-exit idiom to Morry's more moribund morsel.
                                                           Cheers,
                                                           ~Ziggy