535 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
			
		
		
	
	
			535 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
| sunterlib/scsh/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 ]
 | |
| 
 | |
|                                  *
 | |
| 
 | |
| Package Dependencies
 | |
| 
 | |
| SEQUENCES' structures depend on structures from this other sunterlib
 | |
| project:
 | |
|             krims
 | |
| 
 | |
|                                  *
 | |
| 
 | |
| 
 | |
| 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 following procedures, arranged in
 | |
| columns=structures and `* categories' from SRFI-13 and -1, followed
 | |
| by the list of name clashes with standard modules.
 | |
| 
 | |
| 
 | |
| VECTOR-LIB            SEQUENCE-LIB             ABSEQUENCES, also S.L.
 | |
| * 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
 | |
| 
 | |
| * 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)
 | |
| 
 | |
|                                   *
 | |
| 
 | |
| 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 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
 | |
| 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 Examples demonstrate how one might introduce hidden
 | |
| aliasing, i.e. shared subsequences, and break some banged procedures ... ]
 | |
| 
 | |
|                                     *
 | |
| 
 | |
| 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.
 | |
| Assignment is parallel -- if there's no hidden aliasing (s1[j] and s0[k]
 | |
| referring to the same location although j ~= k).
 | |
| 
 | |
|                                  *
 | |
| 
 | |
| (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.
 | |
| Assignment is parallel -- if there's no hidden aliasing.
 | |
| 
 | |
| 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!, 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
 | |
| 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.
 | |
| Doesn't cope with absequent aliasing problems.
 | |
| 
 | |
|                                 *
 | |
| 
 | |
| (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
 |