This site is a static rendering of the Trac instance that was used by R7RS-WG1 for its work on R7RS-small (PDF), which was ratified in 2013. For more information, see Home.

Source for wiki NumericVectorsCowan version 21

author

cowan

comment


    

ipnr

127.11.51.1

name

NumericVectorsCowan

readonly

0

text

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 [http://srfi.schemers.org/srfi-4/srfi-4.html 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.

== Representation types ==

The [type] values are:

 `u8`::
  unsigned 8-bit integer
 `s8`::
  signed 8-bit integer
 `u16`::
  unsigned 16-bit integer
 `s16`::
  signed 16-bit integer
 `u32`::
  unsigned 32-bit integer
 `s32`::
  signed 32-bit integer
 `u64`::
  unsigned 64-bit integer
 `s64`::
  signed 64-bit integer
 `f32`::
  32-bit float
 `f64`::
  64-bit float
 `c64`::
  64-bit complex number
 `c128`::
  128-bit complex number

== Constructors ==

`(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 ''k''th 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]vec''s.

== Predicates ==

`([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.

== Selectors ==

`([type]vector-ref` ''[type]vector k''`)`

Returns a Scheme number corresponding to the ''k''th element of ''[type]vector''.  Note that `u8vector-ref` is the same as the R7RS-small procedure `bytevector-u8-ref`.

== Mutators ==

`([type]vector-set!` ''[type]vector k v''`)`

Converts ''v'' to a binary value encoded according to [type] and places it into the ''k''th 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!`.

== Conversions to numeric vectors ==

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''.

== Conversions from numeric vectors ==

`([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].

== Mapping ==

`([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.

== Input and output ==

`(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.

== TODO ==

{{{
[type]vector-fold, [type]vector-fold-right
[type]vector-unfold, [type]vector-unfold-right, [type]vector-unfold!
[type]vector-index, [type]vector-index-right
[type]vector-skip, [type]vector-skip-right
[type]vector-binary-search
[type]vector-any, [type]vector-every, [type]vector-partition
[type]vector-reverse-copy, [type]vector-reverse-copy!
[type]vector-count, [type]vector-cumulate
[type]vector-swap!, [type]vector-fill!
[type]vector-reverse!, [type]vector-copy!, [type]vector-reverse-copy!
[type]vector-unfold!, [type]vector-unfold-right!
}}}

== Packaging ==

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.

== Implementation ==

[https://gist.github.com/ijp/1e0e67ff93c486f66fc8 This syntax-rules macro by Ian Price] will be helpful in implementing lots of similar but not identical procedures for the 12 types.

time

2016-05-18 04:28:46

version

21