This page is part of the web mail archives of SRFI 44 from before July 7th, 2015. The new archives for SRFI 44 contain all messages, not just those from before July 7th, 2015.
On Tuesday, Oct 21, 2003, at 03:20 US/Eastern, Bradd W. Szonye wrote:
As promised, here is my suggestion for revising the collection procedures. I tried to remain faithful to the original, and I tried to avoid even minor changes. No, really! Nevertheless, I'm sure that it will look like a big change. Therefore, let me preface my revision with some rationales. Feel free to question or reject them -- as you've already seen, I'm amenable to leaving things the way they are if you have a good reason to do so. Organization - With the new attributes like reversible, it was too difficult to organize procedures by collection type. Instead, I listthem all by procedure type (constructor, accessor, etc.) with a "defined for:" clause below each usage example. I think I correctly specified allof the interfaces, but please double-check them if you decide to use this. Dictionaries - I generalized the collection-building procedures to work well with dictionaries. For example, *-add can now build a dictionary; just give it a (cons key value) pair, like you do in the dictionary constructor. Likewise, *-remove can remove a mapped value; it returns the removed key and value as a pair. There's also a specialized *-add-key (for convenience's sake) and *-remove-key (for necessity's sake). I removed the *-put function, but added a note to *-set-key that some dictionaries may permit key addition via that procedure. In other words, the "add-or-set" operation is optional. Removal and deletion - All remove-type procedures now return the modified collection and the removed value. If it's a dictionary, remove returns a key-value pair. Set! compatible with R5RS - The original specification for *-set! was incompatible with R5RS vector-set!, which modifies the vector in-place and returns an unspecified value. I changed *-set! to match that, and Ichanged *-set (the functional version) to return the modified collectionand the previous value.
This doesn't work at all, because *-SET! is _linear_update_, not purely mutable. I am _adamantly_ against removing linear update procedures and replacing them with purely mutable ones, because it just _doesn't_work_ with some kinds of collections, e.g. lists, where the empty list can't be mutated. (This applies to all of the other *-foo! procedures as well.)
*=? and <=?: I added question marks for consistency with functions likestring=?. I also removed the elt= argument and changed the definition sothat it was no longer necessary. I was reluctant to make this change, but I felt that the original version just wasn't viable.
I don't like this at all. Removing ELT= is removing a _lot_ of functionality. The reason the ? wasn't there was _because_ the procedures were not comparable to STRING=?, CHAR=?, et cetera. I don't understand the rationale for having ordering functions on _collections_. Can you explain this in more detail? (or in any detail at all: I can't find any)
The mainproblem, once again, is that a single equivalence predicate just doesn'twork for dictionaries.
It _does_ make sense for dictionaries: if all the keys are equal, _by_ the_dictionary's_key_equivalence_function_, then test to see if all the
I considered passing (cons key=? val=?) to the procedure, but that wouldn't work for non-dictionaries.
Er, I don't get this. You didn't mind changing the add and remove operations to accept pairs for dictionaries, but you do for the comparison operations?
In the end, I went with the *=? interface, partly because it makes for a trivial implementation of string=?.
(define (string=? . strings) (apply string= char=? strings)) That looks pretty trivial to me!
I think that's all of the major changes. Here's the revision: PROCEDURES Many procedures accept an optional procedure (thunk) to handle failure. If a procedure cannot perform the requested operation (because the collection has a fixed size, is immutable, does not permit duplicate values, does not contain a requested value, would become unordered,etc.), it returns the value of invoking the thunk with no arguments. Thedefault thunk signals an error. CONSTRUCTORS [...] procedure: % {key<? | key=?} {val<? | val=?} value ... => % defined for: all collections Constructs a new % collection with the values as its contents. Some collections may require ordering or equivalence functions during construction. Dictionaries may require comparison functions for both keys and values. (Ordered collections should derive their equivalence functions from the ordering function whenever possible.)
The ordering functions here sort of make sense, I guess...but I don't like how they work with these two constructors. It's ambiguous what argument corresponds to what; for example, is (list = 1 2 3) a list with = for a comparison function and (1 2 3) for contents, or a list (#{Procedure} 1 2 3)? (where '#{Procedure}' indicates an abstract procedure value)
procedure: *-copy * => * defined for: all collections Returns a new collection of the same type as the argument with the same contents but distinct storage. The copy is shallow; that is, it copies values in a way that preserves object identity.
I should like a *-COPY for sequences that also accepts optional start and end arguments.
TYPE PREDICATES procedure: collection? value => value procedure: %? value => value defined for: all collections Returns a true value iff the provided value supports the interface for the type (%) named in the predicate.
Why %? and not *??
CARDINALITY OPERATORS procedure: *-empty? collection => boolean
Don't forget the 'defined for: all collections' bit.
[...] procedure: *-size collection => exact integer defined for: all collections If the collection has a concept of size, this function returns the number of values or mappings in the collection. If it does not, #f must be returned. If possible, this should return the number of times collection-fold will call the fold-function before halting.
Have we decided on the issues of infiniteness and circularity yet?
[...] EQUIVALENCE AND TOTAL ORDERING RELATIONS procedure: *=? *... => boolean procedure: *<? *... => boolean
(see far above)
procedure: *-equivalence-function * => procedure defined for: bags, sets, and dictionaries
Where's the rationale for defining this _and_ *-KEY-EQUIVALENCE-FUNCTION on dictionaries?
Returns the value equivalence function for the collection. procedure: *-key-equivalence-function * => procedure defined for: dictionaries Returns the key equivalence function for the dictionary. procedure: *-ordering-function * => procedure defined for: ordered bags, sets, and dictionaries
Again, I don't see why this is defined on dictionaries when there is *-KEY-ORDERING-FUNCTION.
Returns the value ordering function for the collection. procedure: *-key-ordering-function * => procedure defined for: ordered dictionaries Returns the key ordering function for the dictionary. ENUMERATIONS [...] ACCESSORS [...] VALUE MUTATORS
See near the top of this email about this.
procedure: *-update * position f [thunk] => * procedure: *-update! * position f [thunk] => unspecified defined for: sequences and ordered collections procedure: *-update-key * key f [thunk] => * procedure: *-update-key! * key f [thunk] => unspecified defined for: sequences and ordered collections
I don't understand why you're differentiating between these two, and why they aren't defined for dictionaries.
COLLECTION MUTATORS When adding or inserting a value into a dictionary, the new value must be a key-value pair, unless the procedure is specifically defined for dictionaries. Likewise, when removing or deleting a dictionary value, the returned value is a key-value pair. A key-value pair is a Scheme pair whose car is the key and whose cdr is the mapped value: (cons key value). procedure: *-clear[!] * [thunk] => * defined for: all collections Returns an empty collection of the same type as the argument.
[the next bit is permutated and abbreviated bit]
procedure: *-add-key[!] * new-key mapped-value [thunk] => * defined for: dictionaries Returns a collection of the same type with the new key mapped to the given value.
Why have *-ADD with key/value pairs _and_ this?
procedure: *-add-each[!] * source-collection [thunk] => * procedure: *-remove-every[!] * value => * list procedure: *-remove-each-from[!] * source-collection [thunk] => % list procedure: *-remove-every-from[!] * source-collection [thunk] => % list procedure: *-remove-key[!] * key [thunk] => * pair
Why differentiate between removing and removing keys?
procedure: *-remove-every-key[!] * key [thunk] => * list procedure: *-remove-each-key-from[!] * source [thunk] => * list procedure: *-remove-every-key-from[!] * source [thunk] => * list
Er, why all of the name changes?
[...] procedure: *-insert-right * new-value [thunk] => * defined for: reversible sequences
Don't you mean 'reversible _flexible_ sequences?'
[...] procedure: *-delete-right * [thunk] => * defined for: reversible sequences and reversible ordered collections
[flexible]
As *-delete, except that it deletes the value at the end of the sequence. SET OPERATIONS [...] -- Bradd W. Szonye http://www.szonye.com/bradd