some suggestions
Richard Kelsey
(12 Feb 2003 02:03 UTC)
|
Re: some suggestions Phil Bewig (12 Feb 2003 15:25 UTC)
|
Re: some suggestions
Richard Kelsey
(12 Feb 2003 16:22 UTC)
|
Re: some suggestions
Phil Bewig
(13 Feb 2003 15:33 UTC)
|
On Tuesday, February 11, 2003 8:02 PM, Richard Kelsey [SMTP:xxxxxx@s48.org] 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