mori

A library for using ClojureScript's persistent data
structures and supporting API from the comfort of
vanilla JavaScript.

Rationale

JavaScript is a powerful and flexible dynamic
programming language with a beautiful simple
associative model at its core. However this design
comes at the cost of ubiquitous mutability. Mori
embraces the simple associative model but leaves
mutability behind. Mori delivers the following
benefits to JavaScript:

Immutability

Mori delivers highly tuned persistent data structures
based on the ones provided in Clojure. When using
Mori data structures and operations you do not need to
defensively clone as you often do in JavaScript.
By providing immutable data structures, Mori encourages
value oriented programming.

Mori is not an island

Beyond the the core philosophy Mori makes no other
assumptions about how you might use it. In fact, Mori
has changed some aspects of the ClojureScript API in
order to better accomodate usage from JavaScript and
languages that target JavaScript like
CoffeeScript. For example, where it makes sense, Mori
returns regular JavaScript arrays so that you can use
destructuring syntax where available.
The following example is in CoffeeScript:

m = mori;
[a, b] = m.juxt(m.inc, m.dec)(1); // a = 2, b = 0

Using Mori

Mori can be used in precisely the same way that
libraries like Underscore.js are used. Mori of course
provides not only the same functionality but it
delivers a rich set of data structures.
Mori's operators are more general than the ones
provided by Underscore.js - they work on nearly all
the native JavaScript types. In those cases where they
do not work you usually just need to wrap the type
in mori.primSeq(...).

Notation

Each entry is annotated with the signature with an
accompanying description and some relevant
examples. Optional parameters appear
as [option] in the signature. Sometimes
the signature or description will mention coll
for collection. In general collections can be
converted in to sequences for manipulation via the
various sequence operations. This include all Mori
collections as well as JavaScript Arrays and Strings.

All the examples are in JavaScript or CoffeeScript. However,
for simplicity's sake we show the results of operations
in Clojure literal syntax notation.

sorted_map
mori.sorted_map(key0, val0, key1, val1, ...)

set
mori.set(seqable)

Constructs a collection of unique items. You may pass
in any seqable type - this includes JavaScript arrays
and strings. There are several operations unique to
sets which do not apply to the other collections.

nth
mori.nth(coll, index)

Get the value at the specified index. Complexity
depends on the collection. nth is essentially
constant on vector, but linear on lists. For collections
which are not sequential like sets and hash-map, the
collection will be coerced into a sequence first.

var v = mori.vector("foo", "bar", "baz");
mori.nth(v, 1); // => "bar"

last
mori.last(coll)

Get the last value in a collection, in linear time.

var v = mori.vector("foo", "bar", "baz");
mori.last(v); // => "baz"

assocIn
mori.assocIn(coll, keys, val)

Convenience function for assoc'ing nested associative
data structures. keys may be any seqable.

filter
mori.filter(pred, coll)

Return a lazy sequence representing the original
collection filtered of elements which did not return a truthy
value for pred. Note that Mori has a stricter
notion of truth than JavaScript. Only false, undefined, and null
are considered false values.

remove
mori.remove(pred, coll)

The inverse of filter. Return a lazy sequence representing the original
collction filtered of elements which returned a truthy
value for pred. Note that Mori has a stricter
notion of truth than JavaScript. Only false, undefined, and null
are considered false values.

partition
mori.partition(n, [step], [pad], coll)

Partition a seqable collection into groups of n items. An optional step
parameter may be provided to specify the amount of overlap. An additional pad
element can be provided when the final group of items is too small.

Helpers

primSeq
mori.primSeq(seqable, [index])

There are many array-like JavaScript objects which
are not actually arrays. To give these objects a uniform
interface you can wrap them with mori.primSeq.
The optional argument index may be used to
specify an offset. Note this is not necesary for arrays or
strings.

comp
mori.comp(f, g)

juxt
mori.juxt(f0, f1, ...)

Takes a series of functions and creates a single function
which represents their "juxtaposition". When this function
is called, will return the result of each function applied
to the arguments in a JavaScript array.

knit
mori.knit(f0, f1, ...)

This allows you to create functions that work on a heterogenous
collection and return a new collection of the same
arity. It is an relative
of juxt. Like juxt
it takes a series of functions and returns a new
function. Unlike juxt the resulting
function takes a sequence. The functions and sequence
are zipped together and invoked.