Athena
Athena is a library that provides core functional combinators like Curry
,
Compose
, Partial
, etc. Combinators range from lambda calculus, to general
higher-order functions, to logic and control-flow combinators.
Example
var _ = require('athena')
function add2(a, b) { return a + b }
var add = _.curry(add2)
_.compose( _.add(1)
, _.uncurry(add2)
, _.k([2, 3])
)()
Installing
The easiest way is to grab it from NPM (use browserify if you're on a
Browser):
$ npm install athena
If you really want to continue suffering with old and terrible module
systems (or use no module system at all), you can run make dist
yourself:
$ git clone git://github.com/killdream/athena
$ cd athena
$ npm install
$ make dist
# Then use `dist/athena.umd.js` wherever you want.
Platform support
This library assumes an ES5 environment, but can be easily supported in ES3
platforms by the use of shims. Just include es5-shim :3
Tests
$ npm test
API
noop()
Does nothing.
noop: () -> ()
noop(1)
k(a)
The constant function in lambda calculus.
k: A -> () -> A
k(1)(2)
id(a)
The identity function in lambda calculus.
id: A -> A
id(1)
delay(seconds, f)
Executes the given function after (at least) the given seconds.
delay: number -> (A... -> B) -> timer-id
delay(0.5, function(){ console.log(2) })
console.log(1)
defer(f)
Executes the function asynchronously, as soon as possible.
defer: (A... -> B) -> ()
defer(function(){ console.log(2) })
console.log(1)
compose(...)
Function composition (compose(f, g)(x)
= f(g(x))
).
compose: (A... -> B)... -> A... -> B
function double(x){ return x + x }
function squared(x){ return x * x }
var doubleSquared = compose(squared, double)
doubleSquared(2)
curry(arity, f, ...)
Creates a curried function from an uncurried one.
curry: number?, (A... -> B), [A]? -> A... -> (A... -> B) | B
function add(a, b){ return a + b }
var curriedAdd = curry(add)
var add1 = curriedAdd(1)
add1(2)
partial(f, ...)
Partially applies the given arguments to a function.
partial: (A... -> B), A... -> A... -> B
function add(a, b){ return a + b }
var add1 = partial(add, 1)
add1(2)
uncurry(f)
Transforms a curried function to a function on lists.
uncurry: (A... -> B) -> [A] -> B
var toArray = Function.call.bind([].slice)
function add(a, b){ return a + b }
function sum(){ return toArray(arguments).reduce(add, 0) }
sum([1, 2, 3])
uncurryBind(f)
Transforms a curried function to a function on lists, where the first item of
the list is the value of this
.
uncurryBind: (A... -> B) -> [this, A...] -> B
var bag = {
items: [],
add: function() {
this.items.push.apply(this.items, arguments)
}
}
var addToBag = uncurryBind(bag.add)
var otherBag = { __proto__: bag, items: [] }
addToBag([otherBag, 1, 2])
otherBag.items
wrap(advice, f)
Wraps the invocation of f
in the given advice
. The advice
can then decide
what to do with the function.
f: (A... -> B)
wrap: (f, C... -> D) -> f -> C... -> D
function add(a, b) { return a + b }
function trace(f, a, b) {
console.log('Calling %s with: %s, %s', f.name, a, b)
var result = f(a, b)
console.log('Returned: %s', result)
return result
}
var tracedAdd = wrap(trace, add)
tracedAdd(1, 2)
either(predicate, consequent, alternate, ...)
either(p, f, g)(a)
is the same as p(a)? f(a) : g(a)
.
either: (A... -> bool) -> (A... -> B) -> (A... -> C) -> A... -> B | C
function isNegative(a) { return a < 0 }
function negate(a) { return -a }
var abs = either(isNegative, negate, id)
abs(-2)
abs(2)
unless(predicate, consequent, ...)
unless(p, f)(a)
is the same as if (!p(a)) f(a)
.
This is also aliased as _unless
for LiveScript/CoffeeScript.
unless: (A... -> bool) -> (A... -> B) -> A... -> maybe B
function isCallable(a){ return typeof a == 'function' }
function raise(e){ throw new Error(e) }
function unwrap(f){ return f() }
unless(isCallable, unwrap)(function(){ return 1 })
limit(n, f)
Yields a function that will apply f
the first N
times.
limit: number -> (A... -> B) -> (A... -> maybe B)
var f = limit(2, id)
[f(1), f(2), f(3)]
once(f)
Yields a function that will apply f
only once.
once: (A... -> B) -> (A... -> maybe B)
var f = once(id)
[f(1), f(2)]
until(predicate, f)
Yields a function that will only apply f
before the predicate holds.
This is also aliased as _until
for LiveScript/CoffeeScript.
until: (A... -> bool) -> (A... -> B) -> (A... -> maybe B)
function greaterThan(a, b){ return a > b }
function sub(a, b){ return a - b }
var subGreater = until(greaterThan, sub)
subGreater(1, 2)
subGreater(2, 2)
subGreater(3, 2)
subGreater(0, 2)
when(predicate, f)
Yields a function that will only apply f
after the predicate holds.
This is also aliased as _when
for LiveScript/CoffeeScript.
when: (A... -> bool) -> (A... -> B) -> (A... -> maybe B)
function greaterThan(a, b){ return a > b }
function sub(a, b){ return a - b }
var subGreater = when(greaterThan, sub)
subGreater(1, 2)
subGreater(2, 2)
subGreater(3, 2)
subGreater(0, 2)
or(...)
Yields a function that will apply each function in turn, and return the value
of the first truthy one.
This is also aliased as _or
for LiveScript/CoffeeScript.
or: (A... -> B)... -> A... -> maybe B
and(...)
Yields a function that will apply each function in turn, and return the value
of the last truthy one.
This is aliased as _and
for LiveScript/CoffeeScript.
and: (A... -> B)... -> A... -> maybe B
not(f)
Yields a function that will return the negated result of applying f
.
not: (A... -> bool) -> A... -> bool
Licence
MIT/X11. ie.: do whatever you want.