Polymorphic immutable sequences, represented by array slices under the hood to
allow for constant-work random access and reindexing.
All functions here have no side-effects: they do not
modify their inputs and have no implicit state. All functions are also
deterministic, except where stated otherwise.
Contiguous subsequences (produced via subseq
, take
, and drop
) share space
with their input: a sequence remains in memory as long as there is a reference
to it or one of its subsequences.
Parallel functions have an implicit (fairly large) granularity. For more
careful granularity control, see SeqBasis
.
Note that structure ArraySequence = Seq
; these structures are identical
and can be used interchangeably.
In the documentation below, some notational conventions:
|s|
meanslength s
s[i]
meansnth s i
[x,y,z]
meansfromList [x,y,z]
.
type 'a t
type 'a seq = 'a t
The sequence type, with elements of type 'a
.
All functions here require O(1)
work and span.
val length: 'a seq -> int
The length of a sequence, i.e., number of elements.
val nth: 'a seq -> int -> 'a
nth s i
returns the element at index i
of s
.
Requires 0 <= i < length s
.
Raises Subscript
if out-of-bounds.
val first: 'a seq -> 'a
Get the element at index 0; raise Subscript
if empty.
val last: 'a seq -> 'a
Get the element at index n-1
; raise Subscript
if empty.
val subseq: 'a seq -> int * int -> 'a seq
subseq s (i, len)
returns the contiguous subsequence of elements
of length len
starting at index i
.
Requires 0 <= i <= i+len <= length s
.
Raises Subscript
if either out-of-bounds or len
is negative.
val take: 'a seq -> int -> 'a seq
take s k
returns the first k
elements of s
.
Equivalent to subseq s (0, k)
.
val drop: 'a seq -> int -> 'a seq
drop s k
removes the first k
elements of s
.
Equivalent to subseq s (k, length s - k)
.
val empty: unit -> 'a seq
A fresh empty sequence.
val singleton: 'a -> 'a seq
val $ = singleton
Produce a sequence with a single element.
val tabulate: (int -> 'a) -> int -> 'a seq
tabulate f n
produces the sequence [f(0), f(1), ..., f(n-1)]
.
Work: O(sum_i Work(f(i)))
Span: O(max_i Span(f(i)))
val fromList: 'a list -> 'a seq
val % = fromList
Converts a list into a sequence. Linear work and span.
val fromRevList: 'a list -> 'a seq
Reverse a list and convert it into a sequence. Linear work and span.
val toList: 'a seq -> 'a list
Converts a sequence into a list. Linear work and span.
val toString: ('a -> string) -> 'a seq -> string
Produces a string representation of a sequence by first converting each element using the provided function as argument.
Linear work and span.
For example:
toString Int.toString (fromList [1,2,3]) ==> "<1,2,3>"
val append: 'a seq * 'a seq -> 'a seq
Concatenates two sequences. Linear work and constant span.
val append3: 'a seq * 'a seq * 'a seq -> 'a seq
Concatenate three sequences. Linear work and constant span.
val flatten: 'a seq seq -> 'a seq
flatten s
concatenates many sequences.
Work: O(sum_i |s[i]|)
Span: O(log|s|)
For example:
flatten [[0,1,2],[],[3],[4,5],[]] ==> [0,1,2,3,4,5]
val rev: 'a seq -> 'a seq
Reverse the elements of a sequence. Linear work and constant span.
val map: ('a -> 'b) -> 'a seq -> 'b seq
map f s
applies f
to each element to produce
a new sequenece [f(s[0]), f(s[1]), ...]
.
Work: O(sum_i Work(f(s[i])))
Span: O(max_i Span(f(s[i])))
val mapIdx: (int * 'a -> 'b) -> 'a seq -> 'b seq
The same as map
, but the function should expect argument pairs
(i,v)
where v
is the element at index i
.
val enum: 'a seq -> (int * 'a) seq
Pair each element with its index.
Equivalent to mapIdx (fn (i, x) => (i,x))
.
Linear work and constant span.
val zipWith: ('a * 'b -> 'c) -> 'a seq * 'b seq -> 'c seq
zipWith f (s, t)
produces [f(s[0], t[0]), f(s[1], t[1]), ...]
.
That is, it applies function f
to pairs of elements at the same index.
The resulting sequence has length min(|s|,|t|)
.
val zipWith3: ('a * 'b * 'c -> 'd) -> 'a seq * 'b seq * 'c seq -> 'd seq
Same as zipWith
, but for three sequences instead of two.
val zip: 'a seq * 'b seq -> ('a * 'b) seq
A standard zip. Equivalent to zipWith (fn (x,y) => (x,y))
.
val reduce: ('a * 'a -> 'a) -> 'a -> 'a seq -> 'a
reduce f z s
computes the "sum" of s
with respect to f
.
Requires that f
is associative with corresponding identity
z
. When s
is empty, this returns z
.
Assuming f is O(1):
Work: linear
Span: O(log|s|)
For example:
reduce op+ 0 [1,2,3,4,5] ==> 15 reduce op* 1 [1,2,3,4,5] ==> 120 reduce op^ "" ["a","b","c"] ==> "abc"
val scan: ('a * 'a -> 'a) -> 'a -> 'a seq -> 'a seq * 'a
scan f z s
is like reduce, except it also computes the "sum"
of every prefix of s
. The output is (p, t)
where p[i]
is the
sum of the first i
elements, and t
is the total sum (equivalent
to reduce).
Assuming f is O(1):
Work: linear
Span: O(log|s|)
For example:
scan op+ 0 [1,2,3,4,5] ==> ([0,1,3,6,10],15) scan op* 1 [1,2,3,4,5] ==> ([1,1,2,6,24],120) scan op^ "" ["a","b","c"] ==> (["","a","ab"],"abc")
filter, iterate, foldl/r, inject, foreach, etc.