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

Re: some suggestions



On Tuesday, February 11, 2003 8:02 PM, Richard Kelsey [SMTP:kelsey@xxxxxxx] wrote:
> What an impressive amount of work.  In fact, I think it might be a bit
> too impressive.  I would find this all easier to comprehend and use if
> it were split into two SRFIs, one with the basic operations and another
> with all of the utilities that build upon them.  The basic one could
> contain something like:
> 
>      STREAM-NULL
>      STREAM-CONS
>      STREAM
>      STREAM?
>      STREAM-NULL?
>      STREAM-PAIR?
>      STREAM-CAR
>      STREAM-CDR
>      STREAM-MAP
>      STREAM-FOR-EACH
> 

Everyone who has seen a preliminary draft of this SRFI had the same
comment that it should be split into "essential" and "library" pieces,
but all had different ideas of where to make the split.  One favorite was
to split into those that required knowledge of the underlying representation,
but that leaves a very small SRFI with only the constructors NULL and
CONS, the selectors CAR and CDR, the predicates NULL? and PAIR?,
and some kind of LAMBDA, which isn't very practical.  And what do you
do about something like FILTER, which can be implemented without
knowledge of the underlying representation but can use that knowledge
to be much more efficient?  Another possibility I considered but rejected
was to split along the lines of finite/infinite lists; I did this somewhat by
moving some of the finite functions to the example section, but again
the split is imperfect, as many of the functions are useful to both.

R5RS provides some guidance by including some functions on lists
that it clearly labels "library procedures."  This includes a-lists that
are easily build from the essential functions, but that I find very useful
and "fundamental" to the list data type.  R5RS also includes functions
like CADADR that I have never used and probably never will.  And it
omits such useful functions as FOLD and FILTER that are the basis
of many other functions; you could even claim that FOLD should be
included but LENGTH should be excluded, on the grounds that LENGTH
is an easy one-liner given FOLD (I followed that logic when I moved
LENGTH to the example section).  Overall, the guidance from R5RS is
confused.

I don't know where this is leading.  Despite considerable discussion,
I have only a vague feeling about how to split this into two SRFIs.  I
guess my answer is pragmatic; include everything analogous to R5RS
and the haskell prelude on the grounds that anything less leaves users
of the library unsatisfied, then take the time to discuss all the pieces
and produce something truly useful.

> Did you consider using more perspicuous, if less traditional, names?
> 
>   STREAM-NULL  -> EMPTY-STREAM
>   STREAM-CONS  -> MAKE-STREAM
>   STREAM-NULL? -> EMPTY-STREAM?
>   STREAM-PAIR? -> NONEMPTY-STREAM?
>   STREAM-CAR   -> STREAM-HEAD
>   STREAM-CDR   -> STREAM-TAIL
> 

No, not really.  I *like* the traditional names, both on general principles
and on the grounds of consistency.  Why should I add to the burden of
the reader to recognize that MAKE is really CONS in disguise, or add
to the burden of the writer to remember that CDR when applied to
streams is spelled TAIL and not TL, or for that matter REST?  This is
scheme -- it's not haskell, or SML, or even lisp -- and I chose schemely
names even when borrowing semantics from haskell.  I don't want to
choose TAIL on the grounds that CDR was an historical mistake that
needs to be fixed.  And what would you do with CADADR?

On the other hand, I did think hard about some of the names.  A good
example is the INIT in the haskell prelude that I call BUTLAST.  One
reader of a preliminary draft suggested that INIT sounds like something
used for initialization, while BUTLAST (borrowed from the logo language)
clearly says that it takes every element from a stream except the last,
as the tail-end analog of CDR.  The issue is clarity versus consistency
with haskell, and since this is scheme, which has no tradition in this
matter, I chose clarity and changed the name.  Other places where I
had trouble with names are the MERGE, INTERLEAVE, ALTERNATE
and REPEAT, ITERATE families, where I had to invent names because
there is no clear tradition (ALTERNATE was once called ROUND-ROBIN,
on a day when I lacked imagination, and was for a time called CYCLE
before it finally became ALTERNATE).

Choosing names is more a matter of style than engineering, but I have
learned in programming that style is just as important to making programs
work as engineering.  So I welcome discussion about names, but I
think names should be chosen for reasons other than perspicuity or
tradition.  My own personal opinion is that names should be chosen for
the reader rather than the writer, and that while synonyms are good for
natural languages, since the different words can convey slightly different
meanings and thereby enrich the language, the inherent ambiguity of
synonyms is bad for programming languages, since it forces the reader
to consider if there really are two different meanings, or just two words
with the same meaning.  What do other members of the community think?

> Finally, I don't understand why STREAM-DEFINE in the reference
> implementation is not just defined as
> 
>   (define-syntax stream-define
>     (syntax-rules ()
>       ((stream-define spec body0 body1 ...)
>        (define spec
>          (make-stream
> 	   (delay (force (stream-promise (begin body0 body1 ...)))))))))
> 
> If there is a reason for the current definition, you could remove its
> final pattern
> 
>   (stream-define (name args ...) body0 body1 ...)
> 
> because everything that matches this is already matched by the previous
> pattern
> 
>   (stream-define (name . rest) body0 body1 ...)
> 

I am not an expert macrologist.  Neither am I an advanced macrologist.
Even the claim that I am an intermediate macrologist is probably
stretching the truth, although I am learning.  I clearly went overboard
trying to make rest parameters work, and I like your construction much
better than mine.  I'll adopt it in future versions of the reference
implementation, along with the suggestion from felix to change BEGIN
to LET () to allow internal defines.

>                                  -Richard Kelsey
> 	   
> 

Thank you for taking the time to respond.  Critically reading a SRFI
like this one is a task equally as hard as writing it, and I appreciate
your work to help make it better.

Phil