npm install teep
var teep = require('teep');
var a = teep.option(); // none
var b = a.map(function (x) { return x + 1; }); // none
var c = teep.option(41); // some(41)
var d = c.map(function (x) { return x + 1; }); // some(42)
<script src="https://github.com/earldouglas/teep/raw/1.5.1/teep.js"></script>
<script type="text/javascript">
window.teep = window.edc.teep;
</script>
Fire up your browser's JavaScript console from this page, and explore
the teep
object directly.
contains
takes an array and an element, and returns whether the
element exists at least once in the array.
Example:
var yep = teep.array.contains([1,2,3], 2); // true
var nope = teep.array.contains([1,2,3], 4); // false
foldr
performs a right-fold over an array, using z
as the starting
point.
Example:
function sum(xs) {
return teep.array.foldr(xs, 0, function (z, x) {
return z + x;
});
}
sum([1,2,3,4]); // 10
flatten
takes an array of arrays, and returns the concatenation of
each.
Example:
teep.array.flatten([[1,2],[3,4],[5,6]]); // [1,2,3,4,5,6]
map
applies a function over each element in an array, and returns a
new array of the results.
Example:
function plusOne(x) {
return x + 1;
}
teep.array.map([1,2,3,4], plusOne); // [2,3,4,5]
flatMap
applies a function (that itself returns an array) over each
element in an array, and returns an array of the concatenation of the
results.
Example:
function repeatPlusOne(x) {
return [x, x + 1];
}
teep.array.flatMap([1,2,3], repeatPlusOne); // [1,2,2,3,3,4]
filter
returns an array of elements from xs
for which f
returns
true
.
Example:
teep.array.filter([1,2,3,4,5,6], function (x) {
return x % 2 === 1 || x === 4;
}); // [1,2,4,5]
compose
takes two unary functions f
and g
, and combines them into
a single unary function f ∘ g
that applies g
to an input, passes the
output to f
, applies f
to it, and returns the result.
The application of (f ∘ g)(x)
is equivalent to f(g(x))
.
Example:
function inc(x) {
return x + 1;
}
function square(x) {
return x * x;
}
var nine = teep.fn.compose(square, inc)(2); // square(inc(2)) == (2 + 1) ^ 2
var five = teep.fn.compose(inc, square)(2); // inc(square(2)) == (2 ^ 2) + 1
curry
takes an n-ary function f
and an optional array of arguments,
and returns a curried version of f
, comprised of n nested unary
functions where the arity of f
is n.
Example:
function add(x, y) {
return x + y;
}
var add2 = teep.fn.curry(add)(2);
var five = add2(3); // 2 + 3 == 5
Example:
function mathemagic(x, y, z) {
return x * (y + z);
}
var fortyTwo = teep.fn.curry(mathemagic)(2)(20)(1); // 2 * (20 + 1)
memoize
takes a function and an optional cache implementation, and
memoizes the function by backing it with the cache, if supplied, or a
simple object-based cache otherwise.
Example:
function expensiveFn(n) {
for (var i = 0; i < 10000; i++) {
for (var j = 0; j < 10000; j++) {
i = i;
}
}
return n;
}
var cheapFn = teep.fn.memoize(expensiveFn);
var slowResult = cheapFn(42); // expensive computation the first time
var fastResult = cheapFn(42); // cheap cache lookup the second time
lazy
takes a function and an optional cache implementation, and
creates a function that, given input arguments, returns a lazy evaluator
that will apply the function to the arguments only when needed, and only
once if needed many times.
Example:
function expensiveFn(n) {
for (var i = 0; i < 10000; i++) {
for (var j = 0; j < 10000; j++) {
i = i;
}
}
return n;
}
var lazyVal = teep.fn.lazy(expensiveFn)(42); // lazily apply 42 -- no computation yet
var slowResult = lazyVal.get(); // expensive computation the first time
var fastResult = lazyVal.get(); // cheap cache lookup the second time
throttle
limits the rate of application of a function f
, regardless
of how frequently it is called. Call order is preserved.
Arguments:
limit
is the maximum number of applications to allow in aperiod
period
is the duration (in milliseconds) to allow up tolimit
applicationsinterval
is the minimum time (in milliseconds) allowed between applicationsf
is a single-argument function to be throttled
Example:
function f(x) {
...
}
// Don't exceed two f(x) calls per second
var limit = 2;
var period = 1000;
// Space out f(x) calls with 250ms in between
var interval = 250;
var throttledF = teep.fn.throttle(limit, period, interval, f);
// Run f(x) a bunch of times:
// * Don't exceed two per second
// * Don't exceed one every 250ms
throttledF(1);
throttledF(2);
throttledF(3);
throttledF(4);
throttledF(5);
option
constructs a representation of an optional value, represented
as either "some value" or "no value", depending on whether a non-null
argument was supplied.
An option instance exposes the following fields:
empty
- whether this option instance contains a valuemap(f)
- returns a new option by applyingf
over this option's value, and wrapping the result in an optionflatMap(f)
- returns a new option by applyingf
over this option's value, and returning the resultap(a)
- assumes this option wraps a function, and returns a new option by mapping this option's function over the optiona
and returning the resulttoString()
Example:
function parse(x) {
var y = parseInt(x);
if (y) {
return teep.option(y);
} else {
return teep.option();
}
}
parse('forty-two').toString(); // none()
parse('42').toString(); // some(42)
function timesTwo(x) {
return x * 2;
}
parse('21').map(timesTwo).toString(); // some(42)
parse('21').flatMap(function (x) {
return parse('2').map(function (y) {
return x * y;
});
}).toString(); // some(42)
An Either
instance exposes the following fields:
left
- whether this is aLeft
instanceright
- whether this is aRight
instancemap(f)
- returns a newEither
by applyingf
over thisEither
's value, and wrapping the result in anEither
flatMap(f)
- returns a newEither
by applyingf
over thisEither
's value, and returning the resulttoString()
left
constructs a representation of an error-like value, such as an
error message, that can't be used for further computation.
right
constructs a representation of a value that can be used for
further computation.
Example:
function timesTwo(x) {
return x * 2;
}
left('file not found').map(timesTwo).toString(); // left(file not found)
right(21).map(timesTwo).toString(); // right(42)
right('21').flatMap(function (x) {
return right('2').map(function (y) {
return x * y;
});
}).toString(); // right(42)
Given an array of promises and a callback, passes the result of each promise (in order) as an argument to the callback, and returns a single promise that yields the result of the callback.
Any of the promises can be lazy, implemented as a nullary function that returns a promise, and will be retrieved as late as possible.
Example:
var p = teep.promise.collect([
Promise.resolve(2),
Promise.resolve(20),
Promise.resolve(1)
], function (x, y, z) {
return x * (y + z);
});
p.then(function(x) {
console.log(x); // 42
});
p
is congruent to Promise.resolve(2 * (20 + 1))
, or
Promise.resolve(42)
.
valid
constructs a validation representing a valid value.
A validation created by valid
exposes the following fields:
valid
- returns truevalue
- returns the (valid) valuemap(f)
- returns a new (valid) validation by mappingf
over this validation's value and wrapping the in a (valid) validationflatMap(f)
- returns a new validation result by mappingf
over this validation's value and returning the resultap(a)
- assumes this validation wraps a function, and returns a new validation by mapping this validation's function over the validationa
and returning the resulttoString()
invalid
constructs a validation representing an invalid value, and
containing an array of errors.
A validation created by invalid
exposes the following fields:
valid
- returns falseerrors
- returns the array of errorsmap(f)
- returns a this validationflatMap(f)
- returns this validationap(a)
- ifa
is valid, return this validation, otherwise returns a new (invalid) validation containing the concatenation of this validation's errors witha
's errorstoString()
Example:
function parse(x) {
var y = parseInt(x);
if (y) {
return teep.validation.valid(y);
} else {
return teep.validation.invalid([x + ' is not a number']);
}
}
parse('forty-two').toString(); // invalid(forty-two is not a number)
parse('42').toString(); // valid(42)
function multiply(x) {
return function (y) {
return x * y;
};
}
parse('21').map(multiply(2)).toString(); // valid(42)
parse('21').flatMap(function (x) {
return parse('2').map(multiply(x));
}).toString(); // valid(42)
teep.validation.valid(multiply).
ap(parse('21')).
ap(parse('2')).toString(); // valid(42)
teep.validation.valid(multiply).
ap(parse('twenty-one')).
ap(parse('two')).toString(); // invalid(twenty-one is not a number,
// two is not a number)
list
constructs a linked list from a value, head
, representing the
first element in the list, and another list, tail
, representing the
rest of the constructed list. If head
is null, tail
is returned, and
if tail
is null, the empty list is returned.
A list instance exposes the following fields:
head
- the head of this list, if it is not emptytail
- the tail of this list, if it is not emptylength
- returns the length of this listmap(f)
- returns a new list created by applyingf
over this listflatMap(f)
- returns a new list created by applyingf
over this list and concatenating the resultsconcat(l)
- returns the concatenation of this list with ltoString()
Example:
var l = teep.list(1, teep.list(2, teep.list(3, teep.list())));
l.toString(); // cons(1, cons(2, cons(3, nil)));
l.map(function (x) {
return x * 2;
}).toString(); // cons(2, cons(4, cons(6, nil)));
l.flatMap(function (x) {
return teep.list(x, teep.list(x + 0.1, teep.list()));
}).toString(); // cons(1, cons(1.1, cons(2, cons(2.1, cons(3, cons(3.1, nil))))))
var l2 = teep.list(4, teep.list(5, teep.list(6, teep.list())));
l.concat(l2).toString(); // cons(1, cons(2, cons(3, cons(4, cons(5, cons(6, nil))))))
reader
constructs a "dependency injection" context around a function
f
that needs an external context (i.e. the application of an argument)
to run.
A reader instance exposes the following fields:
apply(a)
- applies the bound function with the valuea
map(g)
- returns a new reader by composingf
withg
flatMap(g)
- returns a new reader composingf
withg
, then applying the resulting reader
Example:
var db = {
x: 21,
y: 2,
};
function getX(db) {
return db.x;
}
function timesTwo(x) {
return x * 2;
}
teep.reader(getX).map(timesTwo).apply(db); // 42
function getY(db) {
return db.y;
}
teep.reader(getX).flatMap(function (x) {
return teep.reader(getY).map(function (y) {
return x * y;
});
}).apply(db); // 42
read
returns a reader of identity
, to easily "look up" the context.
Example:
var getX = teep.read.map(function (e) { return e.x; });
var getY = teep.read.map(function (e) { return e.y; });
var r = getX.flatMap(function (x) {
return getY.map(function (y) {
return x * y;
});
});
var e = { x: 6, y: 7, };
r.apply(e); // 42
future
creates a data structure around a function f
that expects a
callback, enabling chaining, combining, and composing of additional
callbacks.
A future instance exposes the following fields:
apply(k)
- applies the bound function with the callbackk
map(g)
- returns a new future by composingf
withg
flatMap(g)
- returns a new future composingf
withg
, then applying the resulting futuresequence(f2)
- returns a new future whose callback expects the results of the functionf
and the futuref2
.
Example:
function async(x) {
return function (f) {
setTimeout(f(x), 1000);
};
}
function log(x) {
console.log(x);
}
teep.future(async(21)).map(function (x) {
return x * 2;
}).apply(log); // 42
teep.future(async(21)).flatMap(function (x) {
return teep.future(async(x * 2));
}).apply(log); // 42
readerT
, like reader
, constructs a context around a function f
that, given an external context, returns another monad
A readerT instance exposes the following fields:
apply(a)
- applies the bound function with the valuea
map(g)
- returns a new readerT by composingf
withg
flatMap(g)
- returns a new readerT composingf
withg
, then binding the resulting monad
Example:
var db = {
x: 21,
y: 2,
};
var getX = function (db) {
return teep.future(function (k) {
return k(db.x);
});
};
function log(x) {
console.log(x);
}
teep.readerT(getX).map(function (x) {
return x * 2;
}).apply(db).apply(log); // 42
function multiplyByY(x) {
return teep.readerT(function (db) {
return teep.future(function (k) {
return k(x * db.y);
});
});
};
teep.readerT(getX).flatMap(multiplyByY).apply(db).apply(log); // 42
state
takes a function of type (S) => { state: S, value: A }
and
wraps it in a data structure exposing the following fields:
apply(s)
- runs the state action with the initial states
map(f)
- returns a new state action that appliesf
, which is a pure function tovalue
flatMap(f)
- returns a new state action that appliesf
, which itself returns a state action, tovalue
Example:
var getX = teep.state(function (db) {
return { state: db, value: db.x };
});
var setX = function (x) {
return teep.state(function (db) {
db.x = x;
return { state: db, value: null };
});
};
getX.apply({ x: 42 }).value; // 42
getX.map(times(7)).apply({ x: 6 }).value; // 42
getX.map(times(7)).flatMap(setX).flatMap(function (x) {
return getX;
}).apply({ x: 6 }).value; // 42