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:

  • Efficient immutable data structures - no cloning required
  • Uniform iteration for all types
  • Value based equality

Modern JavaScript engines like V8, JavaScriptCore, and SpiderMonkey deliver the performance needed to implement persistent data structures well.

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.prim_seq(...).

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.

(1 2 3 4)            ;; list

[1 2 3 4]            ;; vector

{"foo" 1, "bar" 2}     ;; hash map / sorted-map

#{"cat" "bird" "dog"}  ;; set / sorted-set
          

Fundamentals

equals mori.equals(x, y)

Test whether two values are equal. Works on all Mori collections. Note that two seqable values will be tested on deep equality of their contents.

var l0 = mori.list(1,2,3);
var l1 = mori.list(1,2,3);
mori.equals(l0, l1); // => true

var v = mori.vector(1,2,3);
mori.equals(v, l0); // => true

var m0 = mori.js_to_clj({foo: 1});
var m1 = mori.js_to_clj({foo: 1});
mori.equals(m0, m1); // => true
          

hash mori.hash(x)

Returns the hash code for a value. Values for which mori.equals returns true have identical hash codes.

var l = mori.list(1, 2, 3);
var v = mori.vector(1, 2, 3);

mori.hash(l) == mori.hash(v); // => true
          

Type Predicates

is_list mori.is_list(coll)

Test if something is a list-like collection. Lists support efficient adding to the head.

is_seq mori.is_seq(coll)

Test if something is a sequence (i.e. iterable)

is_vector mori.is_vector(coll)

Test if something is a vector-like collection. Vectors support random access. It is efficient to add to the end of a vector.

is_map mori.is_map(coll)

Test if something is a map-like collection. Maps support random access and arbitrary keys.

is_set mori.is_set(coll)

Test if something is a hash set.

is_collection mori.is_collection(coll)

Test if something is a collection - lists, maps, sets, vectors are all collections.

is_sequential mori.is_sequential(coll)

Test if something is sequential. For example vectors are sequential but are not sequences. They can however be converted into something iterable by calling seq on them.

is_associative mori.is_associative(coll)

Test if something is associative - i.e. vectors and maps.

is_counted mori.is_counted(coll)

Test if something can give its count in O(1) time.

is_indexed mori.is_indexed(coll)

Test if something is indexed - i.e. vectors.

is_reduceable mori.is_reduceable(coll)

Test if something is reduceable.

is_seqable mori.is_seqable(coll)

Test if something can be coerced into something iterable.

is_reversible mori.is_reversible(coll)

Test if something can be reversed in O(1) time.

Collections

list mori.list(arg0, arg1, ...)

Constructs an immutable list. Lists support efficient addition at the head of the list. It's important to remember that the cost of operations like mori.nth will be linear in the size of the list.

var l = mori.list(2,3);

mori.cons(1, l); // => (1 2 3)
          

vector mori.vector(arg0, arg1, ...)

Constructs an immutable vector. Vectors support efficient addition at the end. They also support efficient random access. You will probably use mori.vector much more often than mori.list

var v = mori.vector(1,2,3,4);
mori.nth(v, 0); // => 1
          

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

Constructs an immutable hash map. Unlike JavaScript objects Mori PersistentHashMap support complex keys. It's recommended that you only use immutable values for your keys - numbers, strings or a Mori collection.

var m0 = mori.hash_map("foo", 1, "bar", 2);
// m0 = {"foo" 1, "bar" 2}

mori.get(m0, "bar"); // => 2

var m1 = mori.assoc(m0, m.vector(1,2), 3);
// m1 = {"foo" 1, "bar" 2, [1 2] 3}

mori.get(m1, m.vector(1,2)); // => 3
          

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

Like a hash map but keeps its keys ordered.

mori.sorted_map(2, "two", 3, "three", 1, "one"); // {1 "one", 2 "two", 3 "three"}
          

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.

var s = mori.set(["bird", "cat", "dog"]);

mori.conj("dog"); // => #{"bird" "cat" "dog"}
mori.conj("zebra"); // => #{"bird" "cat" "dog" "zebra"}
          

sorted_set mori.sorted_set(arg0, arg1, ...)

Like set but keeps its elements ordered.

mori.seq(mori.sorted_set(3,2,1,3)); // #{1 2 3}
          

range mori.range([start], [end], [step])

Construct a potentially infinite lazy range of values.

With no parameters, a infinite lazy sequence starting at 0 will be returned.

var r = mori.range(); // => (0 1 2 3 …)
          

A single parameter serves as the end (exclusive) argument.

var r = mori.range(10); // => (0 1 2 3 4 5 6 7 8 9)
          

Two parameters serve as start and end.

var r = mori.range(1,5); // => (1 2 3 4)
          

If three parameters are specified, the third serves as a step argument.

var r = mori.range(1,9,2); // => (1 3 5 7)
          

queue mori.queue(arg0, arg1, ...)

Constructs a persistent queue. Queues support efficient addition at the end and removal from the front.

var q0 = mori.queue(1, 2); // => #queue [1 2]
var q1 = mori.conj(q0, 3); // => #queue [1 2 3]

mori.peek(q1); // => 1
mori.pop(q1);  // => #queue [2 3]
mori.rest(q1); // => (2 3)
          

Collection Operations

conj mori.conj(coll, arg0, arg1, ...)

Add something to a collection. The behavior depends on the type of the collection.

var l = mori.list(2,3);
mori.conj(l, 1); // => (1 2 3)

var v = mori.vector(1,2);
mori.conj(v, 3); // => [1 2 3]

var m = mori.hash_map("foo", 1);
mori.conj(m, mori.vector("bar", 2));; // => {"foo" 1 "bar" 2}

var s = mori.set(["cat", "bird", "dog"]);
mori.conj(s, "zebra"); // => #{"cat" "bird" "dog" "zebra"}
          

into mori.into(coll, from)

Add all the items in the second collection to the first one as if calling mori.conj repeatedly.

var l = mori.list(2,3);
var v = mori.vector(1,2);

mori.into(l, v); // => (2 1 2 3)
mori.into(l, l); // => (3 2 2 3)
mori.into(v, l); // => [1 2 2 3]
mori.into(v, v); // => [1 2 1 2]
          

assoc mori.assoc(coll, key0, val0, key1, val1, ...)

Associate a new key-value pair in an associative collection. Works on vectors and maps.

var v = mori.vector("foo", "bar", "baz");
mori.assoc(v, 1, "quux"); // => ["foo" "quux" "baz"]

var m = mori.hash_map("foo", 1);
mori.assoc(m, "bar", 2); // => {"foo" 1 "bar" 2}
mori.assoc(m, "foo", 6); // => {"foo" 6}
          

dissoc mori.dissoc(coll, key0, key1, ...)

Removes keys from an associative collection. Works on maps.

var m = mori.hash_map("foo", 1, "bar", 2, "baz", 3);
mori.dissoc(m, "bar", "baz"); // => {"foo" 1}
          

distinct mori.distinct(coll)

Returns a sequence of the elements of coll with duplicates removed.

var v = mori.vector(1, 1, 2, 3, 3, 4, 5);
mori.distinct(v); // => (1 2 3 4 5)
          

empty mori.empty(coll)

Remove everything from a collection.

var m = mori.hash_map("foo", 1, "bar", 2, "baz", 3);
mori.empty(m); // => {}

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

get mori.get(coll, key, [not-found])

Retrieve a value from a collection.

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

var m = mori.hash_map("foo", 1, "bar", 2);
mori.get(m, "foo"); // => 1
mori.get(m, "baz", "nope"); // => "nope"

          

get_in mori.get_in(coll, keys, [not-found])

Retrieve a value from a nested collection. keys may be any seqable object.

var v = mori.vector("foo", "bar", "baz");
var v2 = mori.vector("quux", v);
mori.get_in(v2, [1, 2]); // => "baz"

var m = mori.hash_map("foo", 1, "bar", 2);
var m2 = mori.hash_map("baz", 3, "quux", m);
mori.get_in(m2, ["quux", "bar"]); // => 2
          

has_key mori.has_key(coll, key)

Returns true if the collection has the given key/index. Otherwise, returns false.

var v = mori.vector("foo", "bar", "baz");
mori.has_key(v, 1); // => true
mori.has_key(v, 9); // => false

var m = mori.hash_map("foo", 1, "bar", 2);
mori.has_key(m, "foo"); // => true
mori.has_key(m, "quux"); // => false

var s = mori.set(["foo", "bar", "baz"]);
mori.has_key(s, "foo"); // => true
mori.has_key(s, "quux"); // => false
          

find mori.find(coll, key)

Returns the key value pair as an array for a given key. Returns null if that key isn't present.

var v = mori.vector("foo", "bar", "baz")
mori.find(v, 2) // => [2, "baz"]
mori.find(v, 9) // null

var m = mori.hash_map("foo", 1, "bar", 2)
mori.find(m, "foo") // => ["foo", 1]
mori.find(m, "quux") // null
          

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"
          

assoc_in mori.assoc_in(coll, keys, val)

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

var h = mori.hash_map("foo", mori.hash_map("bar", 1));
mori.assoc_in(h, ["foo", "baz"], 2); // => {"foo" {"bar" 1, "baz" 2}}
          

update_in mori.update_in(coll, keys, function)

var h = mori.hash_map("foo", mori.vector(1, 2, 3));
mori.update_in(h, ["foo", 1], mori.inc); // => {"foo" [1 3 3]}
          

count mori.count(coll)

Returns the length of the collection.

var l = mori.list("foo", "bar", "baz");
mori.count(l) // 3

var v = mori.vector("foo", "bar", "baz");
mori.count(v) // 3

var s = mori.set(["foo", "bar", "baz"]);
mori.count(s) // 3

var m = mori.hash_map("foo", 1, "bar", 2);
mori.count(m) // 2
          

is_empty mori.is_empty(coll)

Returns true if the collection is empty.

var l = mori.list("foo", "bar", "baz");
mori.is_empty(l); // => false

var v = mori.vector();
mori.is_empty(v); // => true
          

peek mori.peek(coll)

Returns either the first item of a list or the last item of a vector.

var l = mori.list("foo", "bar", "baz");
mori.peek(l) // "foo"

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

pop mori.pop(coll)

Returns either a list with the first item removed or a vector with the last item removed.

var l = mori.list("foo", "bar", "baz");
mori.pop(l) // ("bar" "baz")

var v = mori.vector("foo", "bar", "baz");
mori.pop(v) // ["foo" "bar"]
          

zipmap mori.zipmap(seqable0, seqable1)

Takes two seqable objects and constructs a hash map. The first seqable provides the keys, the second seqable the values.

var keys = ["foo", "bar", "baz"];
var vals = [1, 2, 3];
var h = mori.zipmap(keys, vals); // => {"foo" 1, "bar" 2, "baz" 3}
          

reverse mori.reverse(coll)

Returns a reversed sequence of a collection.

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

Vector Operations

subvec mori.subvec(vector, start, [end])

Returns a subsection of a vector in constant time.

var v = mori.vector("cat", "dog", "bird", "zebra");
mori.subvec(v,1,2); // => ["dog"]
          

Hash Map Operations

keys mori.keys(map)

Returns the keys of a hash map as a sequence.

var m = mori.hash_map("foo", 1, "bar", 2);
mori.into_array(mori.keys(m)); // => [ "foo", "bar" ]
          

vals mori.values(map)

Returns the values of a hash map as a sequence.

var m = mori.hash_map("foo", 1, "bar", 2);
mori.into_array(mori.vals(m)); // => [ 1, 2 ]
          

merge mori.merge(map, m0, m1, ...)

Returns the result of conj-ing the rest of the maps into the first map. If any of the keys exist in the previous map, they will be overridden.

var m = mori.hash_map("foo", 1, "bar", 2);
mori.merge(m, mori.hash_map("bar", 3, "baz", 4)); // => {foo 1, bar 3, baz 4}
          

Set Operations

disj mori.disj(set)

Removes an element from a set.

var s = mori.set(["cat", "dog", "bird"]); // => #{"cat" "bird" "dog"}
s.disj("bird"); // => #{"dog" "cat"}
          

union mori.union(set0, set1, ...)

Returns the union of two sets.

var s0 = mori.set(["cat", "dog"]);
var s1 = mori.set(["zebra", "lion"]);

mori.union(s0, s1); // => #{"lion" "cat" "dog" "zebra"}
          

intersection mori.intersection(set0, set1, ...)

Returns the intersection of two sets.

var s0 = mori.set(["cat", "dog", "mouse"]);
var s1 = mori.set(["dog", "cat", "bird"]);

mori.intersection(s0, s1); // => #{"cat" "dog"}
          

difference mori.difference(set0, set1, ...)

Returns the difference between two sets.

var s0 = mori.set(["cat", "dog", "mouse"]);
var s1 = mori.set(["dog", "cat", "bird"]);

mori.difference(s0, s1); // => #{"mouse" "bird"}
          

is_subset mori.is_subset(seta, setb)

Returns true if seta is a subset of setb.

var s0 = mori.set(["dog", "cat"]);
var s1 = mori.set(["cat", "dog", "bird"]);

mori.is_subset(s0, s1); // => true
          

is_superset mori.is_superset(seta, setb)

Returns true if seta is a superset of setb.

var s0 = mori.set(["cat", "dog", "bird"]);
var s1 = mori.set(["dog", "cat"]);

mori.is_superset(s0, s1); // => true
          

Sequences

first mori.first(coll)

Returns the first element in a collection.

mori.first("foobar"); // => "f"

mori.first([1,2,3]); // => 1

var l = mori.list(1,2,3);
mori.first(l); // => 1

var m = mori.hash_map("foo", 1, "bar", 2);
mori.first(m); // some key-value pair as an array
          

rest mori.rest(coll)

Returns the remaining elements in a collection.

mori.rest("foobar"); // => ("o" "o" "b" "a" "r")

mori.rest([1,2,3]); // => (2 3)

var l = mori.list(1,2,3);
mori.rest(l); // => (2 3)

var m = mori.hash_map("foo", 1, "bar", 2);
mori.rest(m); // remaining key-value pairs
          

seq mori.seq(coll)

Converts a collection whether Mori or JavaScript primitive into a sequence.

mori.seq("foo"); // => ("f" "o" "o")
mori.seq(mori.list()); // => null
          

cons mori.cons(val, coll)

Converts a collection into a sequence and adds a value to the front.

var v = mori.vector(2, 3);
mori.cons(1, v); // => (1 2 3)
          

concat mori.concat(coll0, coll1, ...)

Converts its arguments into sequences and concatenates them.

var r = mori.range(3);
var a = [3, 4, 5];
var l = mori.list(6, 7);
var v = mori.vector(8, 9);
mori.concat(r, a, l, v); // => (0 1 2 3 4 5 6 7 8 9)
          

flatten mori.flatten(coll)

Converts an arbitrarily nested collection into a flat sequence.

var v = mori.js_to_clj([[1, 2], 3, [4], [[5, 6], 7]]);
mori.flatten(v); // => (1 2 3 4 5 6 7)
          

into_array mori.into_array(seq)

Converts a seqable collection, including Mori seqs back into a JavaScript array. Non-lazy.

var lazy = mori.map(mori.inc, [1,2,3]);
mori.into_array(lazy); // => [2,3,4]
          

each mori.each(coll, f)

Iterate over a collection. For side effects.

var xs = mori.map(mori.inc, [1,2,3]);
mori.each(xs, function(n) {
console.log(n);
});

// will print 2 then 3 then 4 at your JS console
          

map mori.map(f, coll0, coll1, ...)

Return a lazy sequence that represents the original collection with f applied to each element. Note that map can take multiple collections This obviates the need for Underscore.js's zip.

var a0 = [1,2,3];

mori.map(mori.inc, a0); // => (2 3 4)

var a1 = [4,5,6];
var a2 = [7,8,9];

mori.map(mori.vector, a0, a1, a2); // => ([1 4 7] [2 5 8] [3 6 9])
          

mapcat mori.mapcat(f, coll0, coll1, ...)

Applies f, which must return a collection, to each element of the original collection(s) and concatenates the results into a single sequence.

var a = mori.seq("abc");
var b = mori.seq("123");
var f = function(x, y) { return mori.list(x, x + y); };

mori.mapcat(f, a, b); // => ("a", "a1", "b", "b2", "c", "c3")
mori.reduce(mori.concat, mori.map(f, a, b)); // => ("a", "a1", "b", "b2", "c", "c3")
          

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.

var a = [0,1,2,3,4,5,7,7,9];

mori.filter(mori.is_even, a0); // => (0 2 4 6 8)
          

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.

var a = [0,1,2,3,4,5,6,7,9];

mori.remove(mori.is_even, a0); // => (1 3 5 7 9)
          

reduce mori.reduce(f, [intial], coll)

Accumulate a collection into a single value. f should be a function of two arguments, the first will be the accumulator, the second will be next value in the sequence.

var a = mori.range(10);

mori.reduce(mori.sum, 0, r); // => 45
          

reduce_kv mori.reduce_kv(f, [initial], map)

A variant of reduce for map-like collections, specifically hash maps and vectors.

var f = function(acc, key, val) { return acc + "(" + key + ":" + val + ")"; };

var m = mori.hash_map("foo", 1, "bar", 2);
mori.reduce_kv(f, "", m); // => "(foo:1)(bar:2)"

var v = mori.vector(5, 7);
mori.reduce_kv(f, "", v); // => "(0:5)(1:7)"
          

take mori.take(n, coll)

Takes n elements from a colletion. Note that coll could be an infinite sequence. This function returns a lazy sequence.

var a = mori.range(); // infinite sequence

mori.take(10, r); // => (0 1 2 3 4 5 6 7 8 9)
          

take_while mori.take_while(pred, coll)

Takes elements from a collection as long as the function pred returns a value other than false, null or undefined. Returns a lazy sequence.

The following example is in CoffeeScript:

a = [0,1,2,3,4,5,6,7,8,9]
mori.take_while ((n) -> n < 5), r // => (0 1 2 3 4)
          

drop mori.drop(n, coll)

Drop n elements from a collection. Returns a lazy sequence.

var a = [0,1,2,3,4,5,6,7,8,9]
mori.drop(5, a); // => (5 6 7 8 9)
          

drop_while mori.interleave(pred, coll)

Drops elements from a collection as long as the function pred returns a value other than false, null or undefined. Returns a lazy sequence.

The following example is in CoffeeScript:

a = [0,1,2,3,4,5,6,7,8,9]

mori.drop_while ((n) -> n < 5), a // => (5 6 7 8 9)
          

some mori.some(pred, coll)

Applies the function pred to the elements of the collection in order and returns the first result which is not false, null or undefined.

var a = [1,2,3,4,5,6,7,8,9];
var f = function(x) { return x % 5 == 0 && x * x; };

mori.some(f, a); // => 25
          

every mori.every(pred, coll)

Returns true if the result of applying the function pred to an element of the collection is never false, null or undefined.

var a = [1,2,3,4,5,6,7,8,9];
var f = function(x) { return mori.is_even(x); };
var g = function(x) { return mori.is_even(x) || mori.is_odd(x); };

mori.every(f, a); // => false
mori.every(g, a); // => true
          

sort mori.sort([cmp], coll)

Sorts the collection and returns a sequence. The comparison function to be used can be given as the first argument.

var a = [4,6,2,7,1,0,9,5,8,3]
var f = function(a, b) { return b - a; };

mori.sort(a); // => (0 1 2 3 4 5 6 7 8 9)
mori.sort(f, a); // => (9 8 7 6 5 4 3 2 1 0)
          

sort_by mori.sort_by(keyfn, [cmp], coll)

Sorts the collection by the values of keyfn on the elements and returns a sequence. The comparison function to be used can be given as the first argument.

var a = [0,1,2,3,4,5,6]
var kf = function(x) { return x * 5 % 7; };
var f = function(a, b) { return b - a; };

mori.map(kf, a); // => (0 5 3 1 6 4 2)

mori.sort_by(kf, a); // => (0 3 6 2 5 1 4)
mori.sort_by(kf, f, a); // => (4 1 5 2 3 6 0)
          

interpose mori.interpose(x, coll)

Interpose a value between all elements of a collection.

var a = [1,2,3]

mori.interpose("foo", a) // => (1 "foo" 2 "foo" 3)
          

interleave mori.interleave(coll0, coll1, ...)

Interleave two or more collections. The size of the resulting lazy sequence is determined by the smallest collection.

var ns = [1,2,3];
var as = ["a", "b", "c"];

mori.interleave(ns, as); // => (1 "a" 2 "b" 3 "c")
          

iterate mori.iterate(f, x)

Creates a lazy sequences of x, f(x), f(f(x)), ...

mori.iterate(mor.inc, 0); // => (0 1 2 3 4 5 ...)
          

repeat mori.repeat([n], x)

Return a lazy of sequence of the value repeated. If given n, the value will only be repeated n times.

The following example is in CoffeeScript:

m    = mori
foos = m.repeat("foo")

m.zipmap [1,2,3], foos // => {1 "foo", 2 "foo", 3 "foo"}
          

repeatedly mori.repeatedly([n], f)

Return a lazy of sequence of calling f, a function which takes no arguments (presumably for side effects). If given n, the function will only be repeated n times.

mori.repeatedly(5, Math.random);
// => (... 5 random floating point numbers ...)
          

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.

var m   = mori,
arr = [0,1,2,3,4,5,6,7,8,9],
ps  = m.partition(2, arr);

m.into_array(m.map(m.into_array, ps));
// => [[0,1],[2,3],[4,5],[6,7],[8,9]]

ps = m.partition(2, 1, arr);
m.into_array(m.map(m.into_array, ps));
// => [[0,1],[1,2],[2,3],[3,4],[4,5],[5,6],[6,7],[7,8],[8,9]]
          

partition_by mori.partition_by(f, coll)

Partition a seqable collection with a new group being started whenever the value of the function f changes.

var v = mori.vector("foo", "bar", "baz", "grapefruit");
var f = function(s) { return s[0]; }

mori.partition_by(f, v); // => (("foo") ("bar" "baz") ("grapefruit"))
          

group_by mori.group_by(f, coll)

Returns a map of the items grouped by the result of applying f to the element.

function even_odd(n) {
return mori.is_even(n) ? "even" : "odd";
}

var r = mori.range(10);
mori.group_by(even_odd, r); // => {"even" (0 2 4 6 8) "odd" (1 3 5 7 9)}
          

Helpers

prim_seq mori.prim_seq(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.prim_seq. The optional argument index may be used to specify an offset. Note this is not necesary for arrays or strings.

function foo() {
var args = mori.prim_seq(arguments);
var f = mori.first(args);
}
          

identity mori.identity(x)

A function which simply returns its argument

mori.identity(5); // => 5
          

constantly mori.constantly(x)

Makes a function that takes any number of arguments and simply returns x.

mori.map(mori.constantly("foo"), mori.range(4)); // => ("foo" "foo" "foo" "foo")
          

inc mori.inc(n)

Adds one to its argument.

mori.inc(1); // => 2

dec mori.dec(n)

Subtracts one from its argument.

mori.dec(1); // => 0

sum mori.sum(a, b)

Add its two arguments together. Useful with mori.reduce.

mori.sum(1,2); // => 3

mori.reduce(mori.sum, 0, mori.range(10)); // 45

is_even mori.is_even(n)

Returns true if the argument is divisible by 2.

is_odd mori.is_odd(n)

Returns true if the argument is not divisible by 2.

comp mori.comp(f, g)

Function composition. The result of mori.comp(f, g)(x) is the same as f(g(x)).

mori.map(mori.comp(mori.is_odd, mori.inc), [1, 2, 3]); // => (false true false)
          

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.

f = mori.juxt(mori.first, mori.last);
f([1, 2, 3, 4, 5, 6]); // => [ 1, 6 ] (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.

var f = mori.knit(function (s) { return s.toLowerCase(); },
            function (s) { return s.toUpperCase(); });
f(["FoO", "bAr"]); // => ["foo", "BAR"]
          

pipeline mori.pipeline(x, f0, f1, ...)

Allows threading a value through a series of functions.

var _ = mori;

_.pipeline(
_.vector(1,2,3),
_.curry(_.conj, 4),
_.curry(_.conj, 5)
); // => [1,2,3,4,5]
          

partial mori.partial(f, x, y, ...)

Partial application. Will return a new function in which the provided arguments have been partially applied.

var _ = mori;
var f = _.partial(_.conj, _.vector(1,2,3));

f(4); // => [1,2,3,4]
f(5); // => [1,2,3,5]
          

curry mori.curry(f, x, y, ...)

Curry arguments to a function.

var _ = mori;
var f = _.curry(_.conj, 4);

f(_.vector(1,2,3)); // => [1,2,3,4]
          

fnil mori.fnil(f, x, y, ...)

Takes a function f and returns a new function that upon receiving an argument, if null, will be replaced with x. fnil may take up to three arguments.

var _ = mori;
var f = function(x) {
return _.update_in(x, ["count"], _.fnil(_.inc, 0));
};

f(_.hash_map()); // => {"count", 1}
          

js_to_clj mori.js_to_clj(x)

Recursively transforms JavaScript arrays into Mori vectors, and JavaScript objects into Mori maps.

var data = {foo: "bar"};
mori.js_to_clj(data); // => {"foo", "bar"}
          

clj_to_js mori.clj_to_js(x)

Recursively transforms Mori values to JavaScript. sets/vectors/lists/queues become Arrays, Keywords and Symbol become Strings, Maps become Objects. Arbitrary keys are encoded to by key->js.

var data = mori.hash_map("foo", "bar");
mori.clj_to_js(data); // => {"foo", "bar"} of type js/Object