mori (original) (raw)

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:

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.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.

(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

equalsmori.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.toClj({foo: 1}); var m1 = mori.toClj({foo: 1}); mori.equals(m0, m1); // => true

hashmori.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

isListmori.isList(coll)

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

isSeqmori.isSeq(coll)

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

isVectormori.isVector(coll)

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

isMapmori.isMap(coll)

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

isSetmori.isSet(coll)

Test if something is a hash set.

isCollectionmori.isCollection(coll)

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

isSequentialmori.isSequential(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.

isAssociativemori.isAssociative(coll)

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

isCountedmori.isCounted(coll)

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

isIndexedmori.isIndexed(coll)

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

isReduceablemori.isReduceable(coll)

Test if something is reduceable.

isSeqablemori.isSeqable(coll)

Test if something can be coerced into something iterable.

isReversiblemori.isReversible(coll)

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

Collections

listmori.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 likemori.nth will be linear in the size of the list.

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

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

vectormori.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

hashMapmori.hashMap(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.hashMap("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_mapmori.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"}

setmori.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(s, "dog"); // => #{"bird" "cat" "dog"} mori.conj(s, "zebra"); // => #{"bird" "cat" "dog" "zebra"}

sortedSetmori.sortedSet(arg0, arg1, ...)

Like set but keeps its elements ordered.

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

rangemori.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 andend.

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)

queuemori.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

conjmori.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.hashMap("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"}

intomori.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]

assocmori.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.hashMap("foo", 1); mori.assoc(m, "bar", 2); // => {"foo" 1 "bar" 2} mori.assoc(m, "foo", 6); // => {"foo" 6}

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

Removes keys from an associative collection. Works on maps.

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

distinctmori.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)

emptymori.empty(coll)

Remove everything from a collection.

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

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

getmori.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.hashMap("foo", 1, "bar", 2); mori.get(m, "foo"); // => 1 mori.get(m, "baz", "nope"); // => "nope"

getInmori.getIn(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.getIn(v2, [1, 2]); // => "baz"

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

hasKeymori.hasKey(coll, key)

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

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

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

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

findmori.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.hashMap("foo", 1, "bar", 2) mori.find(m, "foo") // => ["foo", 1] mori.find(m, "quux") // null

nthmori.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"

lastmori.last(coll)

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

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

assocInmori.assocIn(coll, keys, val)

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

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

updateInmori.updateIn(coll, keys, function)

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

countmori.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.hashMap("foo", 1, "bar", 2); mori.count(m) // 2

isEmptymori.isEmpty(coll)

Returns true if the collection is empty.

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

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

peekmori.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"

popmori.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"]

zipmapmori.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}

reversemori.reverse(coll)

Returns a reversed sequence of a collection.

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

Vector Operations

subvecmori.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

keysmori.keys(map)

Returns the keys of a hash map as a sequence.

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

valsmori.values(map)

Returns the values of a hash map as a sequence.

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

mergemori.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.hashMap("foo", 1, "bar", 2); mori.merge(m, mori.hashMap("bar", 3, "baz", 4)); // => {foo 1, bar 3, baz 4}

Set Operations

disjmori.disj(set)

Removes an element from a set.

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

unionmori.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"}

intersectionmori.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"}

differencemori.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"}

isSubsetmori.isSubset(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.isSubset(s0, s1); // => true

isSupersetmori.isSuperset(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.isSuperset(s0, s1); // => true

Sequences

firstmori.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.hashMap("foo", 1, "bar", 2); mori.first(m); // some key-value pair as an array

restmori.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.hashMap("foo", 1, "bar", 2); mori.rest(m); // remaining key-value pairs

seqmori.seq(coll)

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

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

consmori.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)

concatmori.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)

flattenmori.flatten(coll)

Converts an arbitrarily nested collection into a flat sequence.

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

intoArraymori.intoArray(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.intoArray(lazy); // => [2,3,4]

eachmori.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

mapmori.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])

mapcatmori.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")

filtermori.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.isEven, a0); // => (0 2 4 6 8)

removemori.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.isEven, a0); // => (1 3 5 7 9)

reducemori.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

reduceKVmori.reduceKV(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.hashMap("foo", 1, "bar", 2); mori.reduceKV(f, "", m); // => "(foo:1)(bar:2)"

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

takemori.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)

takeWhilemori.takeWhile(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.takeWhile ((n) -> n < 5), r // => (0 1 2 3 4)

dropmori.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)

dropWhilemori.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.dropWhile ((n) -> n < 5), a // => (5 6 7 8 9)

somemori.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

everymori.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.isEven(x); }; var g = function(x) { return mori.isEven(x) || mori.isOdd(x); };

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

sortmori.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)

sortBymori.sortBy(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.sortBy(kf, a); // => (0 3 6 2 5 1 4) mori.sortBy(kf, f, a); // => (4 1 5 2 3 6 0)

interposemori.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)

interleavemori.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")

iteratemori.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 ...)

repeatmori.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"}

repeatedlymori.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 ...)

partitionmori.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.intoArray(m.map(m.intoArray, ps)); // => [[0,1],[2,3],[4,5],[6,7],[8,9]]

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

partitionBymori.partitionBy(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.partitionBy(f, v); // => (("foo") ("bar" "baz") ("grapefruit"))

groupBymori.groupBy(f, coll)

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

function evenOdd(n) { return mori.isEven(n) ? "even" : "odd"; }

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

Helpers

primSeqmori.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.

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

identitymori.identity(x)

A function which simply returns its argument

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

constantlymori.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")

incmori.inc(n)

Adds one to its argument.

decmori.dec(n)

Subtracts one from its argument.

summori.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

isEvenmori.isEven(n)

Returns true if the argument is divisible by 2.

isOddmori.isOdd(n)

Returns true if the argument is not divisible by 2.

compmori.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.isOdd, mori.inc), [1, 2, 3]); // => (false true false)

juxtmori.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)

knitmori.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"]

pipelinemori.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]

partialmori.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]

currymori.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]

fnilmori.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 _.updateIn(x, ["count"], .fnil(.inc, 0)); };

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

toCljmori.toClj(x)

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

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

toJsmori.toJs(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.hashMap("foo", "bar"); mori.toJs(data); // => {"foo", "bar"} of type js/Object