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

Re: SRFI 61: A more general COND clause (fwd)



On Thu, 6 Jan 2005, Christopher Dutchyn wrote:

> On Thu, 6 Jan 2005, Taylor Campbell wrote:
> 
> > 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.
> 
> Yes; but it's just as surprising to encounter a guard? and then => too.

One could find anything that one is unfamiliar with surprising.  I'm
not sure what you find surprising in specific about that, however, and
the deception that it could look like a procedure call is very specific
& concrete.  Furthermore, the order I chose is more consistent with the
order in which things are evaluated: first the generator, then the
guard, and finally -- conditionally -- the receiver.

> > Also, the guard is usually in that position in similar constructions 
> > that linearize nested conditionals: SYNTAX-CASE, Andrew Wright's MATCH, 
> > &c.
> 
> I don't know MATCH, but SYNTAX-CASE must place fender-expr second because 
> it doesn't have the special "=>" marker.

No, there is no such constraint.  It could just as easily put the guard
first.

>                                           Do you think of the guard as 
> optional?  If so, then you're logically talking about sub-casing the 
> existing => clause, not adding another cond clause syntax.  Recast your 
> proposal in those terms.

If it helps you to think of it that way (with the default guard being
the identity function), go ahead; the way I wrote the specification was
intended to be as simple & straightforward as possible.  I'm not going
to change the wording just because you demand that it better match your
thoughts.

> > 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.
> 
> On what basis do you believe that the value is temporary?  See my comments 
> below.

I was using the word loosely, for the purposes of describing what the
new COND clause does.  'Local' or 'generated' value might have been
better choices of words, but it is not as significant as you make it
out to be.

> > Not only do your suggested workarounds require either writing several
> > new routines for every possible application or inserting clumsy IFs in
> > COND clauses,
> 
> I would construct something like
> (define (anaphoric x) (if x x #f))   ;;make macro and with-values easily
> and get
>  	(cond
>  		(((anaphoric char?) (read-char port)) => (lambda (c) ...))
>  	...)

That is still a workaround that requires inserting a few extra tokens
into the conditional and still exhibits all of the temporary boxing
problems.

> > but they may also require complicating the matter by constructing 
> > temporary boxes to hide #F if it is a possible useful temporary value.
> 
> I don't see how your proposal avoids this ... #F means "go to next clause" 
> for cond.  Maybe I don't understand this point; can you explain?

If #F is considered a useful value -- e.g., as a table entry --, then
it would not work for the conditional part of a (<conditional> =>
<receiver>) clause to return #F, because that would make the clause
fail.  Instead, it must box #F somehow to pass to the receiver, so that
COND doesn't take its result to mean failure, and the receiver must
remove the contents of the box.

> > 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.
> 
> Convince me that the guard will *always* treat the value(s) as temporary: 
> ie. the guard doesn't memoize or perform some other operation that forces 
> it to be a listified anyway.  Otherwise, you can't safely do what you're 
> proposing, unless the guard is so simple that a decent peephole or 
> inter-procedural optimizer can see its way clear to doing this.

I'm not trying to convince you of that.  It isn't true.  What I _did_
argue is that the way it is currently designed is easier to optimize
for most cases than your kludgey workarounds.  Even ignoring boxing of
#F, what you suggest for multiple return values requires boxed lists.
For example, consider your MY-PROJ0 procedure (which probably ought to
have a different name, since it is very different from PROJ0): it takes
any number of arguments; if the first argument is true, it returns a
list containing all of the arguments.  This is harder to analyze &
optimize: even if it is a known procedure, only if either all call
sites are also known or the call is integrated can the list be easily
unboxed by the compiler.

With my design, the list is never returned: it is only propagated to
different procedures in quick succession.  What those procedures do is
immaterial: if the guard stores its argument list somewhere, sure, a
list will have to be allocated.  However, the design I constructed does
not _intrinsically_ necessitate allocating a list, unless the compiler
does not even optimize rest argument propagation.  It is specific to
the guard anyway.

In brief, your workarounds are harder to optimize in the general case,
whereas mine are trivial, unless the specific application intrinsically
uses a heap-allocated list anyway, in which case the point is moot.