A Standard ML library for parallel sequences, designed for the smlpkg package manager. Sequences are implemented by mutable arrays under the hood. The interface is purely functional, and includes a variety of standard functions: tabulate, map, reduce, filter, etc. A secondary interface is included to more directly manipulate mutable arrays.
This library is well optimized and---if compiled with MPL---highly parallel.
There are two source files:
lib/github.com/shwestrick/sml-parseq/sml-parseq.mlblib/github.com/shwestrick/sml-parseq/sml-parseq.mpl.mlb
The .mlb is for use with normal SML (e.g. MLton) and the .mpl.mlb is for use with MPL. Both supply the same interface, described below.
structure Seq: sig type 'a t = 'a ArraySlice.slice type 'a seq = 'a t (** The sequence type. The representation is exposed for convenience, * although this is of course a bit dangerous if using parallelism. * Don't mutate unless you know what you're doing! * * The type name `seq` is for readability in the signature. When using * the library, it is recommended to keep the structure closed, and use * `Seq.t`, for example: * * val x: int Seq.t = ... *) val nth: 'a seq -> int -> 'a val length: 'a seq -> int val empty: unit -> 'a seq val fromList: 'a list -> 'a seq val toList: 'a seq -> 'a list val equal: ('a * 'a -> bool) -> ('a seq * 'a seq) -> bool val toString: ('a -> string) -> 'a seq -> string val subseq: 'a seq -> (int * int) -> 'a seq val take: 'a seq -> int -> 'a seq val drop: 'a seq -> int -> 'a seq val tabulate: (int -> 'a) -> int -> 'a seq val map: ('a -> 'b) -> 'a seq -> 'b seq val rev: 'a seq -> 'a seq val append: 'a seq * 'a seq -> 'a seq val filter: ('a -> bool) -> 'a seq -> 'a seq val flatten: 'a seq seq -> 'a seq val iterate: ('b * 'a -> 'b) -> 'b -> 'a seq -> 'b val reduce: ('a * 'a -> 'a) -> 'a -> 'a seq -> 'a val scan: ('a * 'a -> 'a) -> 'a -> 'a seq -> ('a seq * 'a) val scanIncl: ('a * 'a -> 'a) -> 'a -> 'a seq -> 'a seq val foreach: 'a seq -> (int * 'a -> unit) -> unit val binarySearch: ('a * 'a -> order) -> 'a seq -> 'a -> int val merge: ('a * 'a -> order) -> 'a seq * 'a seq -> 'a seq (** A few different sorting algorithms. *) val samplesort: ('a * 'a -> order) -> 'a seq -> 'a seq val mergesort: ('a * 'a -> order) -> 'a seq -> 'a seq val quicksort: ('a * 'a -> order) -> 'a seq -> 'a seq val countingsort: 'a seq -> (int -> int) (* bucket id of ith element *) -> int (* number of buckets *) -> 'a seq * int seq (* sorted, bucket offsets *) val shuffle: 'a seq -> int -> 'a seq (** Randomly shuffle. The second argument is a seed; using the same * seed will produce exactly the same output each time. *) endstructure SeqBasis: sig type grain = int (** Granularity control parameters always come first, if the function * needs one. *) val for: (int * int) -> (int -> unit) -> unit val foldl: ('b * 'a -> 'b) -> 'b -> (int * int) -> (int -> 'a) -> 'b val tabulate: grain -> (int * int) -> (int -> 'a) -> 'a array (** `tabulate grain (i, j) f` produces the array [f(i), f(i+1), ..., f(j-1)]. *) val reduce: grain -> ('a * 'a -> 'a) -> 'a -> (int * int) -> (int -> 'a) -> 'a (** `reduce grain f b (i, j) g` computes the sum of `g(k)` for `i <= k < j`, * where the sum is taken with respect to f. Note that function f must be * associative, i.e. f(x,f(y,z)) = f(f(x,y),z). The value `b` should be * a left-identity for f: f(b,x) = f(x) *) val scan: grain -> ('a * 'a -> 'a) -> 'a -> (int * int) -> (int -> 'a) -> 'a array (** Similar to reduce, but produces all prefix sums. The output is size * N+1, for both "inclusive" and "exclusive" versions of scan, i.e. the * 0th output element is the identity, and the Nth output element is the * same as the output of `reduce`. *) val filter: grain -> (int * int) -> (int -> 'a) -> (int -> bool) -> 'a array (** `filter grain (i, j) f p` is essentially the same as * `tabulate grain (i, j) f` except that each element f(k) is only included * in the output if the predicate p(k) is satisfied. The relative order of * the output elements is preserved. *) val tabFilter: grain -> (int * int) -> (int -> 'a option) -> 'a array (** A slightly different type for filter. The difference is that * `tabFilter grain (i, j) f` guarantees that each f(k) is only evaluated * exactly once, which is more efficient than a normal filter when the * function is expensive. *) end