> Bradd W. Szonye wrote: >> 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 I >> changed *-set (the functional version) to return the modified >> collection >> and the previous value. Taylor Campbell wrote: > 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 .... OK, that's fine, but then the *-set! procedure needs a different name: 1. In R5RS, *-set! is always purely mutable. 2. Vector-set! already exists with pure-mutable semantics. >> *=? and <=?: I added question marks for consistency with functions >> like string=?. I also removed the elt= argument and changed the >> definition so that 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. OK, I agree. How about this instead: 1. Rename the procedure to *-equal? so that you don't end up with both string= (SRFI-44) and string=? (R5RS). In general, it's best to avoid identifiers that differ by only one character. 2. For dictionaries, if elt=? is a procedure, use it to compare both keys and values, and if elt=? is a pair of procedures, use (car elt=?) to compare keys and (cdr elt=?) to compare values. For all other collections, use elt=? or (cdr elt=?). (Using the dictionary's key-equivalence function wouldn't work -- consider what happens when you try to compare two dictionaries with different KEFs.) By the way, one of the reasons I wanted to get rid of elt=? was to make this more convenient for higher-order functions. If somebody can come up with a reasonable default for elt=? and a syntax for omitting it, that'd be great. If not, we can always use (lambda a (apply *-equal? eqv? a)). > 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) Mainly because sets, sequences, and ordered collections all have well-defined total ordering functions (proper subsets and lexicographical comparisons). Also because it gives users a built-in ordering function for creating ordered collections of collections (which is fairly common in some programming styles). >> procedure: % {key<? | key=?} {val<? | val=?} value ... => % >> defined for: all collections > 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) Sorry, I didn't explain the syntax. The {opt} indicates an optional part of the interface, not an optional argument. For example: procedure: bag val=? value ... => bag procedure: dictionary key=? val=? pair ... => dictionary procedure: ordered-dict key<? val=? pair ... => ordered-dict The arguments aren't optional, but not all constructors use them. >> 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. Yes, that would be good. If provided, I'd prefer "start to end-1" semantics, like C arrays and C++ iterators. >> 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 *?? I didn't think it made a difference in this case. It's defined for all collections, and it has "isa" semantics. If you think * makes more sense, feel free to change it. >> CARDINALITY OPERATORS >> >> procedure: *-empty? collection => boolean > Don't forget the 'defined for: all collections' bit. Oops, thanks. >> 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? I think so, but I'm not certain. We did decide that *-size was a sufficient replacement for finite-collection?. I think we also agree that *-size should return the number of enumerations and that a circular data structure is not necessarily infinite, but I'm not sure. >> procedure: *-equivalence-function * => procedure >> defined for: bags, sets, and dictionaries >> >> procedure: *-ordering-function * => procedure >> defined for: ordered bags, sets, and dictionaries > Where's the rationale for defining these _and_ [the keyed versions] on > dictionaries? To support the "simple" version of *=. Therefore, you can drop dictionaries from the list if you stick with the original *= interface. However, it just occurred to me that there's some ambiguity for ordered-collection -- dictionaries are usually in key order, but other collections are in value order. I think we actually need to separate them into "ordered-collection" and "key-ordered-collection." Otherwise, you'll have problems with polymorphism. >> 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. First, there's a typo: *-update is for sequences, *-update-key is for dictionaries. The reason for having two different functions is because key lookup is *not* the same thing as indexing. I gave them similar names because they're similar, but I didn't merge them because they're orthogonal. Specifically, consider a dictionary that is also a sequence -- hash tables, binary search vectors, and alists are good examples. By having two functions, we can look up values by index or by key. >> 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? Syntactic sugar, mostly. Also for consistency with the other -key functions. >> 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? Because they're two different operations: *-remove takes a value out of a bag, and *-remove-key takes a key out of a dictionary. If you have a dictionary that is also a bag, those need to be two different methods. In other words, this is the same issue as update/update-key above. >> 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? Hm, thought I already explained this. I couldn't get my head around "all" and "any" -- kept thinking that "all" was the one that got rid of all the copies. I dunno whether "every" and "each" is better, but I *strongly* dislike any & all. I chose "each" to mimic "for-each." >> procedure: *-insert-right * new-value [thunk] => * >> defined for: reversible sequences >> >> procedure: *-delete-right * [thunk] => * >> defined for: reversible sequences and reversible ordered collections > Don't you mean 'reversible _flexible_ sequences?' The original version allowed insert-right (but not insert-left) even for non-flexible sequences. And the definition of non-flexible (limited) sequences does permit addition at the end for some sequences. My assumption here would be that fixed-size sequences (and others which do not support end-extension) would call thunk. -- Bradd W. Szonye http://www.szonye.com/bradd