I did a full review of draft #7, but before I could post it, draft #8 came out, which is much easier to understand, so I did another full review of that. Points:
1) In the "Other Examples" section, the lengthy outputs should be folded by hand across reasonable line boundaries. When I try to print the SRFI using Chrome, it forces everything to be displayed by using a small and hard-to-read font size. I ended up removing the section before printing, which means I have not reviewed it.
2) I think the default value should be provided when a specialized array is created, not when a storage class is created. In addition, the maker function of a storage class should be callable with a single argument, in which case the function may return a body full of uninitialized garbage. This is not useful for generalized arrays, but may save time for specialized arrays whose initial values are uninteresting.
3) The SRFI should say that generic-storage-class behaves *as if* the specified definition were used. This allows faster versions of vector-ref, vector-set!, etc. to be used.
4) In the following paragraph, "generic-storage-class" is not in code font.
5) It should be explicitly stated that arrays, specialized arrays, and intervals are disjoint types.
6) The section on specialized arrays is labeled "Global Variable" instead of "Specialized Arrays".
7) It is implied that specialized-array-default-safe? can be mutated. Neither R6RS nor R7RS permits the mutation of exported variables. A SRFI 39 parameter would work, or you could just remove this functionality and require people to pass #t to `specialized-array` if they want a (doubly) safe array.
8) You should make clear what the effects are of mutating the vectors passed to `interval` and returned by `interval-upper-bounds` and `interval-lower-bounds`. I recommend that it be an error, which means none of these operations needs to copy the vectors.
9) The definitions of getters and setters are backward compatible with Common Lisp and other SRFIs, but make for implementation inefficiencies. When a multi-index exists only as a sequence of arguments to a procedure, Scheme requires that the implementation of procedure calls reify the arguments as a list before being passed to the called procedure, and this has to be done *every* time the procedure is called.
If you instead require the caller to reify it as a vector and pass the vector, it can be reified just once and mutated on successive calls. Admittedly, this is somewhat less convenient, but if you want convenience more than performance, (getter (vector 1 2 3)) is only slightly more verbose than (getter 1 2 3), and may indeed allocate less storage.
Using this approach for setters allows the new value to be the last argument rather than the first, in conformity with setters for other data types. It likewise means that the mapping procedure passed to `specialized-array-share` simply accepts a vector and returns a vector, rather than messing with variable arguments and multiple values.
10) I still do not understand why you don't allow the degenerate cases of dimension = 0 (which implies that volume = 1) or upper-bound_i = lower-bound_i for any valid i (which implies that volume = 0). They should just fall out naturally. For example, this allows currying a 1d array to an array of 0d arrays.
I can understand not allowing upper-bound_i < lower-bound_i, because that creates paradoxes: the volume of (interval #(3 1) #(3 1)) is 4, even though it has no elements.
11) Here are some procedures you might want to consider adding:
Constructor: array-tabulate (populates the array with successive calls to a tabulation function with argument 0, 1, 2, ...)
Array-ref and array-set! convenience methods for getting and setting without explicitly retrieving the getter/setter.
Whole-array functions: array-fold (fold in lexicographic order), array-reduce, array-scan (APL), array-count, array-index. All of these are basically equivalent to converting the array to a list and operating on the list, but much more space and time efficient.
Additional simple transformation on all arrays: array-diagonal (returns a 1d array containing the diagonal elements up to the smallest dimension)
Others: array-append (along a specified dimension), array-repeat (append to itself N times along a specified dimension), nested-list->specialized-array (needs number of dimensions), nested-vector->specialized-array, array->nested-list, array->nested-vector, inner product (two procs), outer product (one proc).