sunterlib/scsh/sequences/README

524 lines
17 KiB
Plaintext
Raw Normal View History

2003-02-14 21:39:50 -05:00
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:
2003-02-15 19:32:31 -05:00
* 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
2003-07-27 13:36:26 -04:00
too late.) It contains the following procedures, arranged in
columns=structures and `* categories' from SRFI-13 and -1, followed
by the list of name clashes with standard modules.
2003-02-15 19:32:31 -05:00
2003-07-27 13:36:26 -04:00
VECTOR-LIB SEQUENCE-LIB ABSEQUENCES, also S.L.
2003-02-14 21:39:50 -05:00
* Predicates or so
2003-02-15 19:32:31 -05:00
vector? sequence? absequence?
sequence-behavior?
2003-03-22 17:22:15 -05:00
vector-null? sequence-null?
2003-02-14 21:39:50 -05:00
vector-every sequence-every
vector-any sequence-any
vectors-every sequences-every
vectors-any sequences-any
2003-03-13 13:38:28 -05:00
vector= sequence=
vectors= sequences=
2003-02-14 21:39:50 -05:00
* Constructors
2003-02-15 19:32:31 -05:00
make-vector make-another-sequence make-absequence/behavior
2003-03-20 14:09:05 -05:00
vector
vector-tabulate
absequence/behavior
2003-02-15 19:32:31 -05:00
make-sequence-behavior
make-absequence-record
2003-02-14 21:39:50 -05:00
* List & Sequence Conversion
2003-02-15 19:32:31 -05:00
list->vector list->absequence/behavior
2003-02-14 21:39:50 -05:00
vector->list sequence->list
* Selection
2003-02-15 19:32:31 -05:00
vector-length sequence-length absequence-length
vector-ref sequence-ref absequence-ref
absequence:behavior
2003-02-14 21:39:50 -05:00
vector-copy sequence-copy
2003-02-17 15:27:13 -05:00
sequence-copy/maker
2003-03-22 17:22:15 -05:00
vector-copy! sequence-copy!
2003-02-14 21:39:50 -05:00
subvector subsequence
* Modification
2003-02-15 19:32:31 -05:00
vector-set! sequence-set! absequence-set!
sequence-fill! vector-fill! absequence-fill!
2003-03-20 14:09:05 -05:00
sequence-tabulate! vector-tabulate!
2003-02-14 21:39:50 -05:00
* Reverse & Append
vector-append sequence-append
* Fold, Unfold & Map
2003-02-17 15:27:13 -05:00
vector-map sequence-map
sequence-map/maker
2003-03-22 17:22:15 -05:00
vector-map-into! sequence-map-into!
2003-02-14 21:39:50 -05:00
vector-for-each sequence-for-each
vector-fold sequence-fold
vector-fold-right sequence-fold-right
vectors-map sequences-map
2003-02-15 19:32:31 -05:00
sequences-map/maker
2003-03-22 17:22:15 -05:00
vectors-map-into! sequences-map-into!
2003-02-14 21:39:50 -05:00
vectors-for-each sequences-for-each
vectors-fold sequences-fold
vectors-fold-right sequences-fold-right
2003-07-27 13:36:26 -04:00
* Name clashes with scheme
vector-fill!
list->vector
When using both SCHEME and VECTOR-LIB, you should choose the binding
explicitly, like so:
(open (modify scheme (hide vector-fill!
list->vector))
vector-lib)
2003-02-14 21:39:50 -05:00
*
Prelude
For our purposes, (each valid state of) a sequence with length n maps a
2004-03-14 11:18:11 -05:00
bounded segment of integers [0:n) into a set of Scheme values or objects,
typically Anything or Character. Any kind Sq of sequences with elements
in T supports the following basic operations, whatever the names, with the
2003-02-15 19:32:31 -05:00
obvious jobs:
maker : (make-sq n [e]) --> s
predicate : (sq? x) --> b
2003-02-15 19:32:31 -05:00
getter : (sq-ref s k) --> s[k]
setter : (sq-set! s k x) --> unspec
meter : (sq-length s) --> n
2003-02-14 21:39:50 -05:00
2003-02-15 19:32:31 -05:00
The following kinds of sequences are supported by this facility:
2003-02-14 21:39:50 -05:00
2003-02-15 19:32:31 -05:00
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,
2003-02-15 19:32:31 -05:00
PREDICATE, etc. procedures. They are the official backdoor where
user-defined sequence types enter the general sequence lib. There are
2003-03-23 14:23:12 -05:00
Examples. [ The Examples demonstrate how one might introduce hidden
aliasing, i.e. shared subsequences, and break some banged procedures ... ]
2003-02-14 21:39:50 -05:00
*
The Procedures
Optional [START END] (abbreviating [START [END]]) parameters default to 0
2003-02-15 19:32:31 -05:00
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
2003-02-15 19:32:31 -05:00
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.
2003-03-22 17:22:15 -05:00
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).
2003-02-14 21:39:50 -05:00
* Predicates
2003-02-15 19:32:31 -05:00
(vector? x) --> b0
(sequence? x) --> b1
(absequence? x) --> b2
(sequence-behavior? x) --> b
2003-02-14 21:39:50 -05:00
2003-02-15 19:32:31 -05:00
Synopsis: The obvious type predicates. Note that by the type
inclusions the boolean B0 ==> B1 and B2 ==> B1.
2003-02-14 21:39:50 -05:00
*
2003-03-22 17:22:15 -05:00
(vector-null? s) --> b
(sequence-null? s) --> b
Synopsis: Return B := boolean(s.length = 0).
*
2003-02-15 19:32:31 -05:00
(vector-every foo? s [start end]) --> x
(sequence-every foo? s [start end]) --> x
2003-02-14 21:39:50 -05:00
Synopsis: Return the value x of (and (foo? s[start]) ... (foo? s[end-1])).
*
2003-02-15 19:32:31 -05:00
(vector-any foo? s [start end]) --> x
(sequence-any foo? s [start end]) --> x
2003-02-14 21:39:50 -05:00
Synopsis: Return the value x of (or (foo? s[start]) ... (foo? s[end-1])).
*
2003-02-15 19:32:31 -05:00
(vectors-every foo? s0 s1 ...) --> b
(sequences-every foo? s0 s1 ...) --> b
2003-02-14 21:39:50 -05:00
2003-02-15 19:32:31 -05:00
Synopsis: Return the value x of (and[0<=i<n] (foo? s0[i] s1[i] ...)) with
2003-02-14 21:39:50 -05:00
n := min.k sequence-length sk.
*
2003-02-15 19:32:31 -05:00
(vectors-any foo? s0 s1 ...) --> b
(sequences-any foo? s0 s1 ...) --> b
2003-02-14 21:39:50 -05:00
2003-02-15 19:32:31 -05:00
Synopsis: Return the value x of (or[0<=i<n] (foo? s0[i] s1[i] ...)) with
2003-02-14 21:39:50 -05:00
n := min.k sequence-length sk.
*
2003-03-13 13:38:28 -05:00
(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.
*
2003-02-14 21:39:50 -05:00
Constructors
2003-02-15 19:32:31 -05:00
(make-vector len [fill]) --> s
(make-absequence/behavior sb len [fill]) --> s
2003-02-14 21:39:50 -05:00
Synopsis: Make a fresh vector resp. absequence S (with sequence-behavior
2003-02-15 19:32:31 -05:00
SB) of length LEN (and all elements = FILL).
2003-02-14 21:39:50 -05:00
*
2003-02-15 19:32:31 -05:00
(vector x0 ...) --> s
(absequence/behavior sb x0 ...) --> s
2003-02-14 21:39:50 -05:00
Synopsis: Make a fresh vector (absequence with sequence-behavior SB)
2003-02-15 19:32:31 -05:00
of minimal length with the elements S[0] = X0, ...
2003-02-14 21:39:50 -05:00
*
2003-03-20 14:09:05 -05:00
(vector-tabulate proc len) --> s
Synopsis: Make vector s[0:len) with s[i] := (proc i).
2003-03-22 17:22:15 -05:00
[ after (string-tabulate proc len) rather than (list-tabulate len proc) ]
2003-03-20 14:09:05 -05:00
*
2003-02-15 19:32:31 -05:00
(make-sequence-behavior maker predicate getter setter meter) --> sb
2003-02-14 21:39:50 -05:00
Synopsis: Package the concrete sequence behaviour (basic procedures
2003-02-15 19:32:31 -05:00
listed in the prelude) in the sequence-behavior record SB.
2003-02-14 21:39:50 -05:00
2003-02-15 19:32:31 -05:00
(make-absequence-record sb data) --> abs
Synopsis: Package the sequence-behavior SB and the concrete sequence DATA
in the absequence record ABS.
2003-02-14 21:39:50 -05:00
*
List & Sequence Conversion
2003-03-20 14:09:05 -05:00
(list->vector xs [start end]) --> s
2003-02-15 19:32:31 -05:00
(list->absequence/behavior sb xs [start end]) --> s
2003-02-14 21:39:50 -05:00
2003-02-15 19:32:31 -05:00
Synopsis: Make a new vector (absequence with sequence-behavior SB) S
2003-02-14 21:39:50 -05:00
representing the sequence xs[start],..,xs[end-1].
*
2003-02-15 19:32:31 -05:00
(vector->list s [start end]) --> xs
(sequence->list s [start end]) --> xs
2003-02-14 21:39:50 -05:00
2003-02-15 19:32:31 -05:00
Synopsis: Return xs = (list s[start] ... s[end-1]).
2003-02-14 21:39:50 -05:00
*
2003-02-15 19:32:31 -05:00
(vector-length s) --> n
(sequence-length s) --> n
(absequence-length s) --> n
2003-02-14 21:39:50 -05:00
2003-02-15 19:32:31 -05:00
Synopsis: Return length N of vector / sequence / absequence S.
2003-02-14 21:39:50 -05:00
*
2003-02-15 19:32:31 -05:00
(vector-ref v k) --> v[k]
(sequence-ref s k) --> s[k]
(absequence-ref abs k) --> abs[k]
2003-02-14 21:39:50 -05:00
*
2003-02-15 19:32:31 -05:00
(absequence:behavior abs) --> sb
2003-02-14 21:39:50 -05:00
2003-02-15 19:32:31 -05:00
Synopsis: Return sequence-behavior SB for the concrete sequence
packaged in absequence ABS.
2003-02-14 21:39:50 -05:00
*
2003-02-15 19:32:31 -05:00
(vector-copy s0 [start end]) --> s1
(sequence-copy s0 [start end]) --> s1
(sequence-copy/maker maker s0 [start end]) -- s1
2003-02-14 21:39:50 -05:00
Synopsis: Make new vector resp. sequence (with MAKER)
2003-02-15 19:32:31 -05:00
S1 = < s0[start+i] : i in [0:end-start) >.
[ MAKER intentionally not made third optional arg. ]
2003-02-14 21:39:50 -05:00
*
2003-03-22 17:22:15 -05:00
(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.
2003-03-23 14:23:12 -05:00
Assignment is parallel -- if there's no hidden aliasing (s1[j] and s0[k]
referring to the same location although j ~= k).
2003-03-22 17:22:15 -05:00
*
2003-02-15 19:32:31 -05:00
(subvector s0 start end) --> s1
(subsequence s0 start end) --> s1
2003-02-14 21:39:50 -05:00
2003-02-15 19:32:31 -05:00
Synopsis: s1 := (sequence-copy s0 start end)
2003-02-14 21:39:50 -05:00
*
Modification
2003-02-15 19:32:31 -05:00
(vector-set! s i x) --> unspec
(sequence-set! s i x) --> unspec
(absequence-set! s i x) --> unspec
2003-02-14 21:39:50 -05:00
2003-02-15 19:32:31 -05:00
Synopsis: Set s[i] := x.
2003-02-14 21:39:50 -05:00
*
2003-02-15 19:32:31 -05:00
(vector-fill! s x [start end]) --> unspec
(sequence-fill! s x [start end]]) --> unspec
(absequence-fill! s x [start end]) --> unspec
2003-02-14 21:39:50 -05:00
2003-02-15 19:32:31 -05:00
Synopsis: Set s[i] := x for all i in [start:end) etc.
2003-02-14 21:39:50 -05:00
*
2003-02-14 21:39:50 -05:00
2003-03-20 14:09:05 -05:00
(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. ]
*
2003-02-14 21:39:50 -05:00
Reverse & Append
2003-02-15 19:32:31 -05:00
(vector-append s0 ...) --> s
(sequence-append s0 ...) --> s
2003-02-14 21:39:50 -05:00
2003-02-15 19:32:31 -05:00
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. ]
2003-02-14 21:39:50 -05:00
*
Fold, Unfold & Map
2003-02-15 19:32:31 -05:00
(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
2003-02-14 21:39:50 -05:00
Synopsis: Make new vector / sequence FS representing the sequence
f(s[start]),...,f(s[end-1]) resp.
2003-02-15 19:32:31 -05:00
(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. ]
2003-02-14 21:39:50 -05:00
*
2003-03-22 17:22:15 -05:00
(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.
2003-03-23 14:23:12 -05:00
Assignment is parallel -- if there's no hidden aliasing.
2003-03-22 17:22:15 -05:00
Attention: differing from CL's MAP-INTO, these procs expect
end1 - start1 <= s0.length - start0, i.e. the destination S1 drives the
2003-04-23 15:27:04 -04:00
loop, as with MAP! in SRFI-1. Differing from SEQUENCE-COPY!, two optionals
relate to the destination S1 and one to the source S0 instead of one to the
destination and two to the source. (Why? Because of the different loop
2003-03-22 17:22:15 -05:00
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.
2003-03-23 14:23:12 -05:00
Doesn't cope with absequent aliasing problems.
2003-03-22 17:22:15 -05:00
*
2003-02-15 19:32:31 -05:00
(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
2003-02-14 21:39:50 -05:00
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.
2003-02-14 21:39:50 -05:00
*
2003-02-15 19:32:31 -05:00
(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
2003-02-14 21:39:50 -05:00
2003-02-15 19:32:31 -05:00
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).
2003-02-14 21:39:50 -05:00
Compute
2003-02-15 19:32:31 -05:00
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],...)
2003-02-14 21:39:50 -05:00
with
2003-02-15 19:32:31 -05:00
n := min.k sequence-length sk.
2003-02-14 21:39:50 -05:00
*
2003-02-15 19:32:31 -05:00
(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
2003-02-14 21:39:50 -05:00
2003-02-15 19:32:31 -05:00
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).
2003-02-14 21:39:50 -05:00
Compute
2003-02-15 19:32:31 -05:00
sq = s[start] o ... o s[end-1] o nil, resp.
sq = (s0[0] ...) o ... o (s0[n-1] ...) o nil
2003-02-14 21:39:50 -05:00
with
2003-02-15 19:32:31 -05:00
n := min.k sequence-length sk.
2003-02-14 21:39:50 -05:00
*
2003-02-15 19:32:31 -05:00
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!
2003-02-15 19:32:31 -05:00
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)
2003-02-14 21:39:50 -05:00
2003-02-15 19:32:31 -05:00
; EOF
2003-02-14 21:39:50 -05:00
*
Sela (for now).
oOo