This is a proposal for a simple API for specialized numeric vectors distinguished by their representation type. The u8 type is the same as the R7RS bytevector type, but the other types are all disjoint from all other Scheme types. This API is more restricted than BytevectorsCowan, except that it is possible to dispatch on the different types of numeric vectors. It may be useful for Schemes on the JVM or the CLR to use this API to provide access to the platform's native numeric vectors.
This design subsumes SRFI 4. There are many procedures, but many of them can be easily inlined by even a very dumb compiler, providing high efficiency. The procedures provided in the present proposal are the numeric-vector analogues of the R7RS-small vector API.
The [type] values are:
(make-[type]vector k [ fill ])
Returns a newly allocated numeric vector of length k. Fill is converted to a binary value according to [type] and used to fill the vector; if fill is not specified, the values of the elements are unspecified. It is an error if fill cannot be converted to [type].
([type]vector v ... )
Returns a newly allocated numeric vector of length k, where k is the number of arguments to the procedure. It is filled with the binary values resulting from encoding the v arguments according to [type]. It is an error if an argument cannot be converted to [type].
([type]vector-unfold proc length initial-seed)
Returns a newly allocated [type]vector whose length is length and iterates across each index k between 0 and length, applying proc at each iteration to the current index and current seed, in that order, to receive 2 values: first, the element to put in the kth slot of the new vector and a new seed for the next iteration. Note that the termination condition is different from the unfold procedure of SRFI 1.
Examples:
(s8vector-unfold (lambda (i x) (values x (- x 1))) 10 0) => #s8(0 -1 -2 -3 -4 -5 -6 -7 -8 -9)Construct a vector of the sequence of integers in the range [0,n).
(u8vector-unfold values n) => #u8(0 1 2 ... n-2 n-1)Copy vector.
(f64vector-unfold (λ (i) (vector-ref vector i)) (vector-length vector))([type]vector-unfold-right proc length initial-seed)
Like [type]vector-unfold, but it uses proc to generate elements from right-to-left, rather than left-to-right. The first index used is length - 1. Note that the termination condition is different from the unfold-right procedure of SRFI 1.
Examples:
Construct a vector of pairs of non-negative integers whose values sum to 4.
(u8vector-unfold-right (λ (i x) (values (cons i x) (+ x 1))) 5 0) => #u8((0 . 4) (1 . 3) (2 . 2) (3 . 1) (4 . 0))Reverse vector.
(float64-vector-unfold-right (λ (i x) (values (f64vector-ref vector x) (+ x 1))) (f64vector-length vector) 0)([type]vector-copy [type]vec [start [end]])
Allocates a new [type]vector whose length is end - start and fills it with elements from [type]vec. Examples:
([type]vector-reverse-copy [type]vec [start [end]])
Like [type]vector-copy, but it copies the elements in the reverse order from [type]vec.
([type]vector-append [type]vec ...)
Returns a newly allocated vector that contains all elements in order from the locations in the [type]vecs.
([type]vector? obj)
Returns #t if obj is a [type]vector, and #f if it is not.
([type]vector-empty? [type]vector)
Returns #t if [type]vector has length 0, and #f otherwise.
([type]vector-ref [type]vector k)
Returns a Scheme number corresponding to the kth element of [type]vector. Note that u8vector-ref is the same as the R7RS-small procedure bytevector-u8-ref.
([type]vector-set! [type]vector k v)
Converts v to a binary value encoded according to [type] and places it into the kth element of [type]vector. It is an error if v cannot be converted to [type]. Note that u8vector-set! is the same as the R7RS-small procedure bytevector-u8-set!.
It is an error if a value being used to fill an element of a [type]vector cannot be converted to [type].
(vector->[type]vector vector [start [ end ] ])
Returns a newly allocated [type]vector of length end - start, filled with the corresponding elements of vector.
(list->[type]vector list)
Returns a newly allocated [type]vector whose length is the length of list, filled with the elements of list.
(vector->[type]vector! [type]vector at vector [start [ end ] ])
Writes the elements of vector from start to end into [type]vector starting at at.
(list->[type]vector! list [type]vector at)
Writes the elements of list into [type]vector starting at at.
([type]vector->vector [type]vector [ start [ end ] ])
([type]vector->list [type]vector [ start [ end ] ])
Returns a newly allocated vector or list of length end - start with the elements of [type]vector from start to end.
([type]vector->vector! vector at [type]vector [start [ end ] ])
Writes the elements of [type]vector from start to end into vector starting at at.
== The whole numeric vector ==
([type]vector-length [type]vector)
Returns the length of [type]vector.
([type]vector-copy [type]vector [ [ start ] end ] )
Copies the elements of [type]vector from start to end into a newly allocated [type]vector.
([type]vector-copy! to at from [ [ start ] end ] )
Copies the elements of from from start to end into to starting at at.
[type]vector-append [type]vector ...)
Returns a newly allocated [type]vector whose elements are the concatenation of the elements in [type]vectors. It is an error if the [type]vectors are not all of the same type.
([type]vector-fill! [type]vector fill [ [ start ] end ] )
Stores fill in the elements of [type]vector. An error is signaled if fill cannot be converted to [type].
([type]vector-map proc [type]vector ...)
Returns a newly allocated [type]vector which contains the results of applying proc to the elements of the [type]vectors in an unspecified order.
([type]vector-map! proc output-[type]vector [type]vector ...)
Writes the results of applying proc to the elements of the [type]vectors into the corresponding elements of output-[type]vector in an unspecified order. It is not an error for output-[type]vector to be the same as one of the [type]vectors. Returns an unspecified value.
([type]vector-for-each proc [type]vector ...)
Applies proc to the elements of the [type]vectors in order from first to last and discards the results. Returns an unspecified value.
(read-[type]vector k [ port ])
Read k * b bytes from port into a newly allocated [type]vector and returns it.
(read-[type]vector! [type]vector [ port [ start [ end ] ] ])
Read end * b - start * b bytes from port into [type]vector starting at start. Returns the number of bytes read divided by b, or an eof object if no bytes are available. If the number of bytes available is not a multiple of b, the value of the element of [type]vector for which b bytes are not available is unspecified.
(write-[type]vector [type]vector [ port [ start [ end'' ] ] ])
Write end * b - start * b bytes to port from [type]vector starting at start. Returns an unspecified value.
Since there are many procedures, it makes sense to factor this into separate libraries. Most programs won't require all the representation types, so factoring horizontally into 12 libraries based on that is a simple approach. If the result is still too large, then we can factor vertically based on expected uses for the function. SRFI 4 provides just 8 procedures per type: the basic and multi-argument constructors, the predicate, the basic accessor, the basic mutator, length, and conversion to and from lists.
This syntax-rules macro by Ian Price will be helpful in implementing lots of similar but not identical procedures for the 12 types.