507 lines
16 KiB
Plaintext
507 lines
16 KiB
Plaintext
sunterlib/s48/sequences -- Finite Sequences
|
|
|
|
A sequence library in various structures dealing with
|
|
* abstract sequences defined by their behaviour
|
|
* general sequences or a union type of built-in and abstract sequences
|
|
* vectors in particular
|
|
[ for list and string libraries ,open srfi-1 resp. srfi-13 ]
|
|
|
|
The library comes in three structures:
|
|
* ABSEQUENCES -- basic procedures for abstract sequences, contained in
|
|
* SEQUENCE-LIB -- procedures for general (and abstract) sequences
|
|
* VECTOR-LIB -- procedures for vectors
|
|
|
|
The VECTOR-LIB exports some SCHEME bindings such as VECTOR-REF, redefines
|
|
some SCHEME procedures such as VECTOR-FILL! (to accept optional [start:end)
|
|
parameters) and consists mainly of generic sequence code compiled with
|
|
the basic sequence operation names bound to the corresponding vector
|
|
procedures. The library is neither complete nor tweaked nor tested
|
|
sytematically. (The idea to recycle parts of the srfi-13 code came
|
|
too late.) It contains the folllowing procedures, arranged in
|
|
columns=structures and `* categories' from SRFI-13 and -1.
|
|
|
|
|
|
VECTOR-LIB SEQUENCE-LIB ABSEQUENCES, also SL
|
|
* Predicates or so
|
|
vector? sequence? absequence?
|
|
sequence-behavior?
|
|
vector-null? sequence-null?
|
|
vector-every sequence-every
|
|
vector-any sequence-any
|
|
vectors-every sequences-every
|
|
vectors-any sequences-any
|
|
vector= sequence=
|
|
vectors= sequences=
|
|
|
|
* Constructors
|
|
make-vector make-another-sequence make-absequence/behavior
|
|
vector
|
|
vector-tabulate
|
|
absequence/behavior
|
|
make-sequence-behavior
|
|
make-absequence-record
|
|
|
|
* List & Sequence Conversion
|
|
list->vector list->absequence/behavior
|
|
vector->list sequence->list
|
|
|
|
* Selection
|
|
vector-length sequence-length absequence-length
|
|
vector-ref sequence-ref absequence-ref
|
|
absequence:behavior
|
|
vector-copy sequence-copy
|
|
sequence-copy/maker
|
|
vector-copy! sequence-copy!
|
|
subvector subsequence
|
|
|
|
* Modification
|
|
vector-set! sequence-set! absequence-set!
|
|
sequence-fill! vector-fill! absequence-fill!
|
|
sequence-tabulate! vector-tabulate!
|
|
|
|
* Reverse & Append
|
|
vector-append sequence-append
|
|
|
|
* Fold, Unfold & Map
|
|
vector-map sequence-map
|
|
sequence-map/maker
|
|
vector-map-into! sequence-map-into!
|
|
vector-for-each sequence-for-each
|
|
vector-fold sequence-fold
|
|
vector-fold-right sequence-fold-right
|
|
vectors-map sequences-map
|
|
sequences-map/maker
|
|
vectors-map-into! sequences-map-into!
|
|
vectors-for-each sequences-for-each
|
|
vectors-fold sequences-fold
|
|
vectors-fold-right sequences-fold-right
|
|
|
|
*
|
|
|
|
Prelude
|
|
|
|
For our purposes, (each valid state of) a sequence with length n maps a
|
|
bounded segment of integers [0:n) into a set of Scheme values, typically
|
|
Anything or Character. Any kind Sq of sequences with elements in T
|
|
supports the following basic operations, whatever the names, with the
|
|
obvious jobs:
|
|
maker : (make-sq n [e]) --> s
|
|
predicate : (sq? x) --> b
|
|
getter : (sq-ref s k) --> s[k]
|
|
setter : (sq-set! s k x) --> unspec
|
|
meter : (sq-length s) --> n
|
|
|
|
|
|
The following kinds of sequences are supported by this facility:
|
|
|
|
Vector
|
|
Absequence := a record type (record packages data + behaviour)
|
|
Sequence := Vector | Byte-Vector | String | Proper-List | Absequence
|
|
|
|
Absequences carry a SEQUENCE-BEHAVIOR record that contains MAKER,
|
|
PREDICATE, etc. procedures. They are the official backdoor where
|
|
user-defined sequence types enter the general sequence lib. There are
|
|
Examples.
|
|
|
|
*
|
|
|
|
The Procedures
|
|
|
|
Optional [START END] (abbreviating [START [END]]) parameters default to 0
|
|
resp. the sequence length. An optional MAKER parameter defaults to
|
|
the maker of the actual type of the (first) sequence argument.
|
|
Sequence arguments of vector and absequence procedures must be vectors
|
|
resp. absequences, notwithstanding the generic parameter name S used below.
|
|
Sequence arguments of general sequence procedures may have different
|
|
actual sequence types, e.g. (SEQUENCES-EVERY CHAR=? "abc" '#(#\a)) is
|
|
ok since both String and Vector <= Sequence.
|
|
|
|
Equivalences
|
|
as far as the specs go, that is: the equivalences don't extend to
|
|
unspecified behaviour but I didn't bother to spell this out in detail.
|
|
The stated equivalences may have to suffer from exceptions as the
|
|
library grows, but please report deviations anyway.
|
|
|
|
* (sequences-foo x ...) = (sequence-foo x ...) and
|
|
(vectors-foo x ...) = (vector-foo x ...)
|
|
if the arg.list is admissible for both procedures.
|
|
[ SEQUENCES-procedures don't support optional [start:end)
|
|
parameters; SEQUENCE-procedures don't support an arbitrary number
|
|
of sequence arguments. Same for vectors. ]
|
|
|
|
* if all sequence arguments to a general sequence procedure are
|
|
vectors the result is that of the corresponding vector procedure.
|
|
E.g. ``sequence-map = vector-map'' on vectors.
|
|
|
|
* if all sequence arguments to a general sequence procedure are lists
|
|
(strings) and there is a corresponding list (string) procedure in
|
|
the respective srfi, the result complies with the srfi spec.
|
|
E.g. ``sequences-fold = fold'' on lists,
|
|
``sequence-fold = string-fold'' on strings.
|
|
Attention:
|
|
SEQUENCE= vs. STRING= -- parameter lists don't match (ELT=)
|
|
SEQUENCE-TABULATE! (and VECTOR-TABULATE) --
|
|
parameter list is patterned after (STRING-TABULATE proc len), not
|
|
after (LIST-TABULATE len proc).
|
|
|
|
* Predicates
|
|
|
|
(vector? x) --> b0
|
|
(sequence? x) --> b1
|
|
(absequence? x) --> b2
|
|
(sequence-behavior? x) --> b
|
|
|
|
Synopsis: The obvious type predicates. Note that by the type
|
|
inclusions the boolean B0 ==> B1 and B2 ==> B1.
|
|
|
|
*
|
|
|
|
(vector-null? s) --> b
|
|
(sequence-null? s) --> b
|
|
|
|
Synopsis: Return B := boolean(s.length = 0).
|
|
|
|
*
|
|
|
|
(vector-every foo? s [start end]) --> x
|
|
(sequence-every foo? s [start end]) --> x
|
|
|
|
Synopsis: Return the value x of (and (foo? s[start]) ... (foo? s[end-1])).
|
|
|
|
*
|
|
|
|
(vector-any foo? s [start end]) --> x
|
|
(sequence-any foo? s [start end]) --> x
|
|
|
|
Synopsis: Return the value x of (or (foo? s[start]) ... (foo? s[end-1])).
|
|
|
|
*
|
|
|
|
(vectors-every foo? s0 s1 ...) --> b
|
|
(sequences-every foo? s0 s1 ...) --> b
|
|
|
|
Synopsis: Return the value x of (and[0<=i<n] (foo? s0[i] s1[i] ...)) with
|
|
n := min.k sequence-length sk.
|
|
|
|
*
|
|
|
|
(vectors-any foo? s0 s1 ...) --> b
|
|
(sequences-any foo? s0 s1 ...) --> b
|
|
|
|
Synopsis: Return the value x of (or[0<=i<n] (foo? s0[i] s1[i] ...)) with
|
|
n := min.k sequence-length sk.
|
|
|
|
*
|
|
|
|
(vector= elt= s0 s1 [start0 end0 start1 end1]) --> b
|
|
(sequence= elt= s0 s1 [start0 end0 start1 end1]) --> b
|
|
|
|
Synopsis: Return boolean(S0 and S1 represent the same sequence), i.e.
|
|
B = (and (elt= s0[start0] s1[start1]) ...)
|
|
[ deviates from STRING= in SRFI-13 due to ELT= parameter ]
|
|
|
|
*
|
|
|
|
(vectors= elt= s0 ...) --> b
|
|
(sequences= elt= s0 ...) --> b
|
|
|
|
Synopsis: Return B = boolean(S0, ... represent the same sequence), i.e.
|
|
B = #t given <2 sequence args, and
|
|
= (and[k=0,...) (sequence= elt= s(k) s(k+1))) otherwise.
|
|
|
|
*
|
|
|
|
Constructors
|
|
|
|
(make-vector len [fill]) --> s
|
|
(make-absequence/behavior sb len [fill]) --> s
|
|
|
|
Synopsis: Make a fresh vector resp. absequence S (with sequence-behavior
|
|
SB) of length LEN (and all elements = FILL).
|
|
|
|
*
|
|
|
|
(vector x0 ...) --> s
|
|
(absequence/behavior sb x0 ...) --> s
|
|
|
|
Synopsis: Make a fresh vector (absequence with sequence-behavior SB)
|
|
of minimal length with the elements S[0] = X0, ...
|
|
|
|
*
|
|
|
|
(vector-tabulate proc len) --> s
|
|
|
|
Synopsis: Make vector s[0:len) with s[i] := (proc i).
|
|
[ after (string-tabulate proc len) rather than (list-tabulate len proc) ]
|
|
|
|
*
|
|
|
|
(make-sequence-behavior maker predicate getter setter meter) --> sb
|
|
|
|
Synopsis: Package the concrete sequence behaviour (basic procedures
|
|
listed in the prelude) in the sequence-behavior record SB.
|
|
|
|
(make-absequence-record sb data) --> abs
|
|
Synopsis: Package the sequence-behavior SB and the concrete sequence DATA
|
|
in the absequence record ABS.
|
|
|
|
*
|
|
|
|
List & Sequence Conversion
|
|
|
|
(list->vector xs [start end]) --> s
|
|
(list->absequence/behavior sb xs [start end]) --> s
|
|
|
|
Synopsis: Make a new vector (absequence with sequence-behavior SB) S
|
|
representing the sequence xs[start],..,xs[end-1].
|
|
|
|
*
|
|
|
|
(vector->list s [start end]) --> xs
|
|
(sequence->list s [start end]) --> xs
|
|
|
|
Synopsis: Return xs = (list s[start] ... s[end-1]).
|
|
|
|
*
|
|
|
|
(vector-length s) --> n
|
|
(sequence-length s) --> n
|
|
(absequence-length s) --> n
|
|
|
|
Synopsis: Return length N of vector / sequence / absequence S.
|
|
|
|
*
|
|
|
|
(vector-ref v k) --> v[k]
|
|
(sequence-ref s k) --> s[k]
|
|
(absequence-ref abs k) --> abs[k]
|
|
|
|
*
|
|
|
|
(absequence:behavior abs) --> sb
|
|
|
|
Synopsis: Return sequence-behavior SB for the concrete sequence
|
|
packaged in absequence ABS.
|
|
|
|
*
|
|
|
|
(vector-copy s0 [start end]) --> s1
|
|
(sequence-copy s0 [start end]) --> s1
|
|
(sequence-copy/maker maker s0 [start end]) -- s1
|
|
|
|
Synopsis: Make new vector resp. sequence (with MAKER)
|
|
S1 = < s0[start+i] : i in [0:end-start) >.
|
|
[ MAKER intentionally not made third optional arg. ]
|
|
|
|
*
|
|
|
|
(vector-copy! s1 start1 s0 [start0 end0]) --> unspec
|
|
(sequence-copy! s1 start1 s0 [start0 end0]) --> unspec
|
|
|
|
Synopsis: Set s1[start1 + i] := s0[start0 + i] for 0 <= i < end0 - start0.
|
|
|
|
*
|
|
|
|
(subvector s0 start end) --> s1
|
|
(subsequence s0 start end) --> s1
|
|
|
|
Synopsis: s1 := (sequence-copy s0 start end)
|
|
|
|
*
|
|
|
|
Modification
|
|
|
|
(vector-set! s i x) --> unspec
|
|
(sequence-set! s i x) --> unspec
|
|
(absequence-set! s i x) --> unspec
|
|
|
|
Synopsis: Set s[i] := x.
|
|
|
|
*
|
|
|
|
(vector-fill! s x [start end]) --> unspec
|
|
(sequence-fill! s x [start end]]) --> unspec
|
|
(absequence-fill! s x [start end]) --> unspec
|
|
|
|
Synopsis: Set s[i] := x for all i in [start:end) etc.
|
|
|
|
*
|
|
|
|
(vector-tabulate! s start proc len) --> s
|
|
(sequence-tabulate! s start proc len) --> s
|
|
|
|
Synopsis: Set s[start+i] := (proc i) for all i in [0:len), return s.
|
|
[ Destructive-update analogue to STRING-TABULATE, exceptionally with a
|
|
useful return value. ]
|
|
|
|
*
|
|
|
|
|
|
Reverse & Append
|
|
|
|
(vector-append s0 ...) --> s
|
|
(sequence-append s0 ...) --> s
|
|
|
|
Synoposis: Make a new vector resp. sequence S = `s0 o ...'. If there
|
|
is no argument, make S a vector, otherwise type(S) = type(S0). [ You
|
|
can force the result type by choosing a suitable empty sequence S0.
|
|
E.g. (sequence-append (vector) "sloty" '(5 5)) works.
|
|
Of course, VECTOR-APPEND always produces vectors from vectors. ]
|
|
|
|
*
|
|
|
|
Fold, Unfold & Map
|
|
|
|
(vector-map f s [start end]) --> fs
|
|
(vectors-map f s0 ...) --> fs
|
|
(sequence-map f s [start end]) --> fs
|
|
(sequence-map/maker maker f s [start end]) --> fs
|
|
(sequences-map f s0 s1 ...) --> fs
|
|
(sequences-map/maker maker f s0 s1 ...) --> fs
|
|
|
|
Synopsis: Make new vector / sequence FS representing the sequence
|
|
f(s[start]),...,f(s[end-1]) resp.
|
|
(f(s0[i],...) : 0<=i<n) with n = min.k sequence-length sk.
|
|
Use the MAKER, if supplied, otherwise the maker of the first sequence
|
|
arg's concrete type. [ MAKER intentionally not made third optional
|
|
arg. ]
|
|
|
|
*
|
|
|
|
(vector-map-into! s1 proc s0 [start1 end1 start0]) --> s1
|
|
(sequence-map-into! s1 proc s0 [start1 end1 start0]) --> s1
|
|
|
|
Synopsis: Set s1[start1 + i] := (proc s0[start0 + i])
|
|
for 0 <= i < end1 - start1, return s1.
|
|
|
|
Attention: differing from CL's MAP-INTO, these procs expect
|
|
end1 - start1 <= s0.length - start0, i.e. the destination S1 drives the
|
|
loop, as with MAP! in SRFI-1. Differing from SEQUENCE-COPY!, the optionals
|
|
relate 2 to the destination S1 and 1 to the source S0 instead of 1 to the
|
|
destination and 2 to the source. (Why? Because of the different loop
|
|
termination criteria: dest length vs. src length.)
|
|
|
|
*
|
|
|
|
(vectors-map-into! s1 proc s00 ...) --> s1
|
|
(sequences-map-into! s1 proc s00 ...) --> s1
|
|
|
|
Synopsis: Set s1[i] := (proc s00[i] ...) for i in [0:s1.length), return s1.
|
|
|
|
Attention: differing from CL's MAP-INTO, these procs expect the sequences
|
|
S00, ... to be no less long than the destination S1, like MAP! in SRFI-1.
|
|
|
|
*
|
|
|
|
(vector-for-each proc s [start end]) --> unspec
|
|
(vectors-for-each f s0 s1 ...) --> unspec
|
|
(sequence-for-each proc s [start end]) --> unspec
|
|
(sequences-for-each proc s0 s1 ...) --> unspec
|
|
|
|
Synopsis: Call (proc v[i]) for all i in [start:end) in some order, resp.
|
|
call (proc v0[i] v1[i] ...) for all i in [0:n) in some order with
|
|
n = min.k sequence-length sk.
|
|
|
|
*
|
|
|
|
(vector-fold kons nil s [start end]) --> sq
|
|
(vectors-fold kons nil s0 s1 ...) --> sq
|
|
(sequence-fold kons nil s0 [start end]) --> sq
|
|
(sequences-fold kons nil s0 s1 ...) --> sq
|
|
|
|
Synopsis: Let y o x := (kons x y) resp.
|
|
y o (x0, x1, ...) := (kons x0 ... y),
|
|
|
|
and let o be left-associative (so that we can spare us the brackets).
|
|
Compute
|
|
sq = nil o s[start] o ... o s[end-1], resp.
|
|
sq = nil o (s0[0],s1[0],...) o ... o (s0[n-1],s1[n-1],...)
|
|
with
|
|
n := min.k sequence-length sk.
|
|
|
|
*
|
|
|
|
(vector-fold-right kons nil s [start end]) --> sq
|
|
(vectors-fold-right kons nil s0 s1 ...) --> sq
|
|
(sequence-fold-right kons nil s [start end]) --> sq
|
|
(sequences-fold-right kons nil s0 s1 ...) --> sq
|
|
|
|
Synopsis: Let x o y := (kons x y) resp.
|
|
(x0,x1,...) o y := (kons x0 ... y),
|
|
|
|
and let o be right-associative (so that we can spare us the brackets).
|
|
Compute
|
|
sq = s[start] o ... o s[end-1] o nil, resp.
|
|
sq = (s0[0] ...) o ... o (s0[n-1] ...) o nil
|
|
with
|
|
n := min.k sequence-length sk.
|
|
|
|
*
|
|
|
|
Examples:
|
|
; Demo implementation of partial sequences
|
|
; ,open sequence-lib srfi-9 krims
|
|
|
|
(define-record-type :shaseq
|
|
(make-shaseq-record sequence start end)
|
|
shaseq?
|
|
(sequence shaseq:sequence)
|
|
(start shaseq:start)
|
|
(end shaseq:end))
|
|
|
|
|
|
(define (share-sequence s start end)
|
|
(assert (<= 0 start end (sequence-length s)))
|
|
(make-shaseq-record s start end))
|
|
|
|
|
|
(define (displace-index shas k)
|
|
(let ((start (shaseq:start shas)))
|
|
(+ start k)))
|
|
|
|
|
|
;; maker -- dummyish
|
|
(define (make-shaseq len . maybe-fill)
|
|
(make-shaseq-record (apply make-vector len maybe-fill)
|
|
0 len))
|
|
;; getter
|
|
(define (shaseq-ref shas k)
|
|
(sequence-ref (shaseq:sequence shas)
|
|
(displace-index shas k)))
|
|
;; setter
|
|
(define (shaseq-set! shas k x)
|
|
(sequence-set! (shaseq:sequence shas)
|
|
(displace-index shas k)
|
|
x))
|
|
;; meter
|
|
(define (shaseq-length shas)
|
|
(- (shaseq:end shas)
|
|
(shaseq:start shas)))
|
|
|
|
|
|
(define shaseq-behavior
|
|
(make-sequence-behavior make-shaseq shaseq?
|
|
shaseq-ref shaseq-set!
|
|
shaseq-length))
|
|
|
|
(define a-string (string-copy "brachman foo gratz bladotzky"))
|
|
(define an-abs (make-absequence-record shaseq-behavior
|
|
(share-sequence a-string 3 11)))
|
|
|
|
;; prints ``(c h m a n f o)''
|
|
(display (sequence-fold-right cons '() an-abs))
|
|
|
|
;; prints ``>>> chman fo <<<''
|
|
(display (sequence-append ">>> " an-abs '#(#\ #\< #\< #\<)))
|
|
|
|
(sequence-fill! an-abs #\X 4)
|
|
;; prints ``brachmaXXXXo gratz bladotzky''
|
|
(display a-string)
|
|
|
|
; EOF
|
|
*
|
|
|
|
Sela (for now).
|
|
|
|
oOo
|