Re: SRFI 61: A more general COND clause (fwd) Taylor Campbell 06 Jan 2005 23:50 UTC

On Thu, 6 Jan 2005, Christopher Dutchyn wrote:

> I'm unconvinced of the utility of your proposal.  First, I would recommend
> placing the guard before the generator, it reads so much better.  Your examples
> become:
>  	(char? (read-port port) => (lambda (c) ...))
> and
>  	(proj0 (table-entry <table> <key>) => (lambda (present? value) ...))
>
> It becomes clear that you're just distingishing the number of terms before the
> =>; R5RS section 4.2.1 gave a single alternate for (<test> => <exp>).

That sounds reasonable.  I'll consider it.  However, it might be a bit
deceptive or confusing in the syntax, in that it looks like a regular
procedure call at first, though it's not.  Also, the guard is usually
in that position in similar constructions that linearize nested
conditionals: SYNTAX-CASE, Andrew Wright's MATCH, &c.

> But, once I write your examples in the more legible way, I realize that I
> already have what I want using the accepted definition that only #f is false
> (R5RS section 6.3.1):
>
> (define anaphoric-char? (lambda (c) (if (char? c) c #f)))
> (define myproj0 (lambda p?v (if (car p?v) p?v #f)))
>
> and your examples in R5RS syntax become
>
>  	((anaphoric-char? (read-port port)) => (lambda (c) ...))
> and
>  	((myproj0 (table-entry <table> <key>)) => (lambda p?v ...))
>
> Is there something about your proposal that I'm missing?

Yes.  What you suggest here are some workarounds for the real problem,
which is having more general way to conditionalize.  Essentially, this
proposal more cleanly separates the condition from a temporary value
that is useful if the condition holds true, while the existing COND =>
syntax multiplexes the temporary value and the condition.

Not only do your suggested workarounds require either writing several
new routines for every possible application or inserting clumsy IFs in
COND clauses, but they may also require complicating the matter by
constructing temporary boxes to hide #F if it is a possible useful
temporary value.  This overhead is also necessary in order to support
multiple possibly useful temporary values, which you must store in a
temporary list; such a list is harder for a compiler to optimize than
the way I have designed it.

(The way I have designed it, the temporary rest argument list used by
the second argument to the CALL-WITH-VALUES is both ephemeral and used
only as the second argument to APPLY, in immediate succession.  This is
trivial for a compiler to optimize into code that just reuses the same
registers or the same stack frame for the arguments to the guard and
the receiver.  With your workarounds, however, the list has arbitrary
extent, and it is operated on with heap-accessing list processing
routines.)

(By the way, your MY-PROJ0 example wouldn't work.  It would need to
instead be (CALL-WITH-VALUES (LAMBDA () (TABLE-ENTRY TABLE KEY))
MY-PROJ0), given the way I described TABLE-ENTRY.)