Skip to content

Latest commit

 

History

History
444 lines (322 loc) · 10.7 KB

1.1.md

File metadata and controls

444 lines (322 loc) · 10.7 KB

Teep 1.1.x

Usage

Node.js

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)

HTML

<script src="https://github.com/earldouglas/teep/raw/1.1.0/teep.js"></script>
<script type="text/javascript">
  window.teep = window.edc.teep;
</script>

JavaScript console

Fire up your browser's JavaScript console from this page, and explore the teep object directly.

Features

Array

array.contains(xs, x)

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

Function

fn.compose(f, g)

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

fn.curry(f, args)

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)

fn.memoize(f, cache)

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

fn.lazy(f, cache)

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

Option

option(value)

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
  • map(f) - returns a new option by applying f over this option's value, and wrapping the result in an option
  • flatMap(f) - returns a new option by applying f over this option's value, and returning the result
  • ap(a) - assumes this option wraps a function, and returns a new option by mapping this option's function over the option a and returning the result
  • toString()

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)

Promise

promise.collect(promises, callback)

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)

Validation

validation.valid(value)

valid constructs a validation representing a valid value.

A validation created by valid exposes the following fields:

  • valid - returns true
  • value - returns the (valid) value
  • map(f) - returns a new (valid) validation by mapping f over this validation's value and wrapping the in a (valid) validation
  • flatMap(f) - returns a new validation result by mapping f over this validation's value and returning the result
  • ap(a) - assumes this validation wraps a function, and returns a new validation by mapping this validation's function over the validation a and returning the result
  • toString()

validation.invalid(errors)

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 false
  • errors - returns the array of errors
  • map(f) - returns a this validation
  • flatMap(f) - returns this validation
  • ap(a) - if a is valid, return this validation, otherwise returns a new (invalid) validation containing the concatenation of this validation's errors with a's errors
  • toString()

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

list(head, tail)

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 empty
  • tail - the tail of this list, if it is not empty
  • length - returns the length of this list
  • map(f) - returns a new list created by applying f over this list
  • flatMap(f) - returns a new list created by applying f over this list and concatenating the results
  • concat(l) - returns the concatenation of this list with l
  • toString()

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

reader(f)

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 value a
  • map(g) - returns a new reader by composing f with g
  • flatMap(g) - returns a new reader composing f with g, 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

Future

future(f)

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 callback k
  • map(g) - returns a new future by composing f with g
  • flatMap(g) - returns a new future composing f with g, then applying the resulting future
  • sequence(f2) - returns a new future whose callback expects the results of the function f and the future f2.

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

readerT(f)

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 value a
  • map(g) - returns a new readerT by composing f with g
  • flatMap(g) - returns a new readerT composing f with g, 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