Sign Up for Free

RunKit +

Try any Node.js package right in your browser

This is a playground to test code. It runs a full Node.js environment and already has all of npm’s 400,000 packages pre-installed, including athena with all npm packages installed. Try it out:

var athena = require("athena")

This service is provided by RunKit and is not affiliated with npm, Inc or the package authors.

athena v0.2.0

Strategically gives you awesome functional combinators for an abstraction war!

Athena Build Status Dependencies Status

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])
         )()
// => 6

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

browser support

Tests

$ npm test

API

noop()

Does nothing.

noop: () -> ()
noop(1) // => undefined

k(a)

The constant function in lambda calculus.

k: A -> () -> A
k(1)(2) // => 1

id(a)

The identity function in lambda calculus.

id: A -> A
id(1) // => 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)
// 1
// 2

defer(f)

Executes the function asynchronously, as soon as possible.

defer: (A... -> B) -> ()
defer(function(){ console.log(2) })
console.log(1)
// 1
// 2

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) // => 16

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) // => 3

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) // => 3

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]) // => 6

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 // => [1, 2]

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)
// Calling add with: 1, 2
// Returned: 3
// => 3

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) // => 2
abs(2) // => 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 }) // => 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)] // => [1, 2, undefined]

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)] // => [1, undefined]

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) //=> undefined
subGreater(2, 2) //=> undefined
subGreater(3, 2) //=> 1
subGreater(0, 2) //=> -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) //=> -1
subGreater(2, 2) //=> 0
subGreater(3, 2) //=> undefined
subGreater(0, 2) //=> undefined

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.

Metadata

RunKit is a free, in-browser JavaScript dev environment for prototyping Node.js code, with every npm package installed. Sign up to share your code.
Sign Up for Free