functional

Gen­eric lib­rary for func­tional pro­gram­ming & work­ing with func­tions.

Source:

Methods

(inner) apply(args, fn) → {*}

Source:
See:

Ap­ply a list of ar­gu­ments to a func­tion.

This is very sim­ilar to Func­tion.pro­to­type.ap­ply(), or the spread syn­tax.

What makes this func­tion spe­cial is that it is cur­ried, so it can ac­tu­ally be used to trans­form a func­tion tak­ing mul­tiple ar­gu­ments into on tak­ing a single ar­ray.

const { stric­tEqual: as­sertIs } = re­quire('assert');
const { plus, ap­ply, zip2, as­sertSequenceEquals, map } = re­quire('fer­rum');

// Us­age like the spread op­er­ator (you should prob­ably just use
// the spread op­er­ator...)
const args = [5, 6];
as­sertIs(plus(...args),     11);
as­sertIs(ap­ply(args, plus), 11);

// Here is an ex­ample of how to use ap­ply to trans­form a func­tion into
// one that takes it's ar­gu­ments as a list…e.g. to clev­erly im­ple­ment
// a func­tion that can sum to vec­tors
const sum­Vec = (a, b) => map(zip2(a, b), ap­ply(plus));
as­sertSequenceEquals(
  sum­Vec([2, 4, 6], [3, 6, 9]),
  [5, 10, 15]);

// This could also be writ­ten with the usual spread op­er­ator
const sum­Vec2 = (a, b) => map(zip2(a, b), (pair) => plus(...pair));
as­sertSequenceEquals(
  sum­Vec2([2, 4, 6], [3, 6, 9]),
  [5, 10, 15]);
Parameters:
Name Type Description
args Array
fn function

The func­tion to ap­ply to

Returns:

Whatever the func­tion re­turns

Type
*

(inner) apply1(arg, fn) → {Any}

Source:
See:

Calls a func­tion with a single para­meter.

const as­sert = re­quire('assert');
const { plus, ap­ply1, let_in, exec, ap­ply, pipe, mul } = re­quire('fer­rum');

as­sert.stric­tEqual(ap­ply1(3, plus(2)), 5);

// As you may ima­gine, this func­tion is a bit use­less,
// be­cause javas­cript has syn­tax sugar for func­tion ap­plic­a­tion
// which is called…func­tion ap­plic­a­tion.
as­sert.stric­tEqual(plus(2)(3), 5);
as­sert.stric­tEqual(plus(3, 2), 5);

// In pretty much any situ­ation you could use ap­ply1,
// you could also just ap­ply the func­tion dir­ectly.
// However, in some situ­ations, ap­ply1 ac­tu­ally looks nicer.
// E.g. you can use ap­ply1 like a let … in state­ment.
// Which is why ap­ply1 is aliased as let_in
as­sert.stric­tEqual(
 let_in(14, (a) =>
   let_in(32, (b) =>
     (a*a) + (b*b) + (2*a*b))),
 2116) // (14 + 32)**2 = 2166;

// Which looks much nicer than this, even with nicer in­dent­a­tion
as­sert.stric­tEqual(
 ((a) =>
   ((b) =>
     (a*a) + (b*b) + (2*a*b)
   )(32)
 )(14),
 2116) // (14 + 32)**2 = 2166;

// Of course you could al­ways just use vari­ables nor­mally;
// e.g. use exec() to open a scope so the vari­ables do not
// leak out­side where they are needed.
as­sert.stric­tEqual(
  exec(() => {
    const a = 14;
    const b = 32;
    re­turn (a*a) + (b*b) + (2*a*b);
  }),
  2116);

// You could even use ap­ply as a more con­cise let…in state­ment;
// which ver­sion you like most is of course up to you, but I quite
// like the let_in vari­ant be­cause it is writ­ten in a func­tional style,
// does not leak vari­ables, very con­cise and still easy to read. But
// that is a mat­ter of taste.
as­sert.stric­tEqual(
 ap­ply([14, 32], (a, b) =>
   (a*a) + (b*b) + (2*a*b)),
 2116); // (14 + 32)**2 = 2166;

// Fi­nally, an­other place where this can come in handy
// is in­side a pipe to ap­ply some cus­tom func­tion to the
// value.
as­sert.stric­tEqual(
  pipe(
    2,
    mul(3), // 6
    ap­ply1((x) => x**x), // Raise X to it­self
    plus(-1)),
  46655);

// Of course it per­fectly works to just sup­ply the func­tion
// it­self dir­ectly, it just looks a bit odd and op­er­ator pre­ced­ence
// looks a bit odd
as­sert.stric­tEqual(
  pipe(
    2,
    mul(3), // 6
    (x) => x**x, // Raise X to it­self
    plus(-1)),
  46655);

// This is es­pe­cially rel­ev­ant for multi line func­tions,
// e.g. you could sup­ply de­bug out­put like this!
as­sert.stric­tEqual(
  pipe(
    2,
    mul(3), // 6
    ap­ply1((x) => x**x), // Raise X to it­self
    plus(-1)),
  46655);

Ver­sion his­tory

  • 1.9.0 Ini­tial im­ple­ment­a­tion
Parameters:
Name Type Description
arg *
fn function
Returns:

Whatever the func­tion re­turns

Type
Any

(inner) call(fn, args) → {*}

Source:
See:

Calls a func­tion.

const as­sert = re­quire('assert');
const {
  call, ap­ply, plus, mul, ap­ply1, each, get, map,
  as­sertSequenceEquals, com­pose, pipe,
} = re­quire('fer­rum');

// Ar­gu­ments are given as a se­quence
as­sert.stric­tEqual(call(plus, [2,3]), 5)

// This is the same as ap­ply(), but with re­versed para­met­ers
// Par­tial ap­plic­a­tion on ap­ply turns a func­tion into one that
// takes a se­quence of ar­gu­ments, while par­tial ap­plic­a­tion on
// call stores a list of ar­gu­ments for re­use.
as­sert.stric­tEqual(ap­ply([2,3], plus), 5);

// call() can be par­tially ap­plied; this is ba­sic­ally stor­ing
// a list of ar­gu­ments, that can be ap­plied to dif­fer­ent func­tions.
const a2_5 = call([2, 5]);
as­sertSequenceEquals(
  map(
    [plus, mul, (x, y) => x**y],
    a2_5),
  [7, 10, 32]); // 2+5, 2*5, 2^5

// This pat­tern could be used to in­voke event hand­lers
const hand­lers = [];
const fire = (param) => each(hand­lers, call([param]));

// In clas­sic javas­cript this would look something like this
const fire2 = (param) => {
  hand­lers.map((fn) => fn(param));
};

// Or without Ar­ray::map
const fire3 = (param) => {
  for (const fn of hand­lers) {
    fn(param);
  }
};

// You could also use this as part of a pipeline to in­voke
// a func­tion.
const ops = {
  plus,
  mul,
  pow: (a, b) => a**b,
};
const eval­u­ate = (op, a, b) => pipe(
  get(ops, op),
  call([Num­ber(a), Num­ber(b)]));
as­sert.stric­tEqual(eval­u­ate("plus", 2, 3), 5);
as­sert.stric­tEqual(eval­u­ate("mul", 2, 3), 6);
as­sert.stric­tEqual(eval­u­ate("pow", 2, 3), 8);

Ver­sion his­tory

  • 1.9.0 Ini­tial im­ple­ment­a­tion
Parameters:
Name Type Description
fn function
args Sequence
Returns:

Whatever the func­tion re­turns

Type
*

(inner) compose(…fns) → {function}

Source:

Func­tion com­pos­i­tion.

This es­sen­tially be­haves like pipe() without tak­ing the ini­tial ar­gu­ment: ex­ecuted left-to-right/​top-to-bot­tom.

const { stric­tEqual: as­sertIs } = re­quire('assert');
const { com­pose, plus, mul } = re­quire('fer­rum');

const fn = com­pose(plus(2), mul(3), x => `My Num­ber ${x}`);
as­sertIs(fn(4), 'My Num­ber 18');
Parameters:
Name Type Attributes Description
fns function <repeatable>

Mul­tiple func­tions

Returns:

All the func­tions in the se­quence com­posed into one

Type
function

(inner) curry(name, fn) → {function}

Source:

Auto­curry a func­tion!

ht­tps://​en.wiki­pe­dia.org/​wiki/​Cur­ry­ing

Any func­tion that has a fixed num­ber of para­met­ers may be cur­ried! Cur­ried para­met­ers will be in re­verse or­der. This is use­ful for func­tional pro­gram­ming, be­cause it al­lows us to use func­tion para­met­ers in the suf­fix po­s­i­tion when us­ing no cur­ring:

const { stric­tEqual: as­sertIs, throws: as­sertThrows } = re­quire('assert');
const { as­sertSequenceEquals, iter, curry } = re­quire('fer­rum');

// De­clare a cur­ried func­tion
const fmt = curry('fmt', (a, b) => `${a} | ${b}`);
as­sertIs(fmt.name, 'fmt [CURRY]');

// Now you de­rive a sec­ond­ary func­tion like this:
const fmtZ = fmt('Z');

// And fi­nally use it. No­tice how the para­met­ers are
// ap­plied in re­verse or­der?
as­sertIs(fmtZ('Y'), 'Y | Z');

// Re­verse or­der is not ap­plied when we spe­cify mul­tiple ar­gu­ments.
// In this ex­ample, ar­gu­ments are ap­plied in the or­der you would
// nor­mally ex­pect.
as­sertIs(fmt(1, 2), '1 | 2');

// This prop­erty is use­ful for func­tions like the iter­ator map func­tion…
const map = curry('map', func­tion* (seq, fn) {
  for (const v of iter(seq)) {
    yield fn(v);
  }
});
as­sertIs(map.name, 'map [CURRY]');

// We can curry map with the func­tion, as you would ex­pect
const ad­dOn­e­ToE­ach = map(x => x+1);
as­sertSequenceEquals(
  ad­dOn­e­ToE­ach([1,2,3]),
  [2, 3, 4]);

// We can use the map func­tion either at once, with the func­tion in the pre­fix
// po­s­i­tion. This is a lot more con­veni­ent than hav­ing the func­tion as the first
// ar­gu­ment, es­pe­cially for func­tions that span mul­tiple lines.
as­sertSequenceEquals(
  map([1, 2, 3], (x) => x+1),
  [2, 3, 4]);

// When a func­tion has mul­tiple para­met­ers this rule is pretty much the same,
// ar­gu­ments ap­plied to­gether in nor­mal or­der, ar­gu­ments ap­plied in sep­ar­ate
// steps are in re­verse or­der. This keeps the func­tion as the last para­meter
// in most cases.
const foldl = curry('foldl', (seq, init, fn) => {
  let r = init;
  for (const v of iter(seq)) {
    r = fn(r, v);
  }
  re­turn r;
});
as­sertIs(foldl.name, 'foldl [CURRY]');

// Ap­plies init, fn
const sum = foldl(0, (a, b) => a+b);

// Fi­nally ap­plies the se­quence
as­sertIs(sum([1, 2, 3]), 6);

// Cur­ried func­tions will throw when in­voked with the wrong num­ber
// of ar­gu­ments
as­sertThrows(() => sum(1, 2, 3));
Parameters:
Name Type Description
name String

The name to given to the func­tion

fn function

The func­tion to curry

Returns:

The curry­able func­tion!

Type
function

(inner) exec(fn)

Source:

Im­me­di­ately ex­ecute the given func­tion.

const { stric­tEqual: as­sertIs } = re­quire('assert');
const {exec} = re­quire('fer­rum');

// Nor­mal scopes can­not re­turn val­ues
let r;
{
  let x = 42, y = 5;
  r = x + y;
}
as­sertIs(r, 47);;

// Can be re­writ­ten as
const q = exec(() => {
  let x = 42, y = 5;
  re­turn  x + y;
});
as­sertIs(q, 47);;
Parameters:
Name Type Description
fn function
Returns:

Whatever the given func­tion re­turns.

(inner) identity(T) → {T}

Source:

Just a func­tion that re­turns it's ar­gu­ment!

const { stric­tEqual: as­sertIs } = re­quire('assert');
const { as­sertSequenceEquals, iden­tity, fil­ter } = re­quire('fer­rum');

as­sertIs(iden­tity(null), null);
as­sertIs(iden­tity(42),   42);

// Iden­tity is some­times use­ful in higher or­der func­tions like
// fil­ter(); this ex­ample for in­stance re­moves all val­ues from
// the list that are falsy
as­sertSequenceEquals(
  fil­ter([null, "asd", "", 42], iden­tity),
  ["asd", 42]);
Parameters:
Name Type Description
T a
Returns:

The para­meter

Type
T

(inner) let_in(arg, fn) → {Any}

Source:
See:

Tem­por­ar­ily define a vari­able in the scope of an ex­pres­sion.

This really is just an alias for ap­ply1() which in turn is just syn­tax sugar func­tion ap­plic­a­tion. Check out the ap­ply1 doc­u­ment­a­tion.

const as­sert = re­quire('assert');
const { let_in } = re­quire('fer­rum');

// Us­ing let_in al­lows you to define a vari­able that
// does not leak out­side an ex­pres­sion.
const y = let_in(6, (x) => x**x + x)
as­sert.stric­tEqual(y, 46662);

// Without let_in this could be writ­ten like this; which
// is sub­op­timal if x is not be­ing used again…
const x = 6;
const y2 = x**x + x;
as­sert.stric­tEqual(y2, 46662);

// You could also use it as syn­tax sugar to avoid a func­tion
// body; e.g. here pre­pro­cessing is used to turn x into a num­ber
const fx = (xString) =>
  let_in(Num­ber(xString), (x) =>
    x**x + x);
as­sert.stric­tEqual(fx("6"), 46662);

// Which de­sug­ars into a func­tion with a const vari­able
// and a re­turn state­ment; which is a bit more verb­ose,
// but will look much more fa­mil­liar to javas­cript de­velopers
const fx2 = (xString) => {
  const x = Num­ber(xString);
  re­turn x**x + x;
};
as­sert.stric­tEqual(fx2("6"), 46662);

Ver­sion his­tory

  • 1.9.0 Ini­tial im­ple­ment­a­tion
Parameters:
Name Type Description
arg *
fn function
Returns:

Whatever the func­tion re­turns

Type
Any

(inner) pipe(val, …fns) → {*}

Source:

Pipeline a value through mul­tiple func­tion calls.

const { as­sertSequenceEquals, pipe, fil­ter, uniq, map, plus, iden­tity } = re­quire('fer­rum');

// Some­times you want to use a lot of se­quence trans­form­a­tions;
// When you nest them this gets very hard to read
as­sertSequenceEquals(
  map(
    uniq(
      fil­ter(
        [1, 2, null, 3, 4, null, 5, 1, 3, 2, null, 1, 4],
        iden­tity
      )
    ),
    plus(2)),
  [3, 4, 5, 6, 7]);

// Pipe lets you re­format this com­plex, nes­ted ex­pres­sion so that
// the trans­former that is first ap­plied, is men­tioned first in the
// pipeline. Note that cur­ry­ing is used to make func­tions like fil­ter
// or map work nicely with pipe
as­sertSequenceEquals(
  pipe(
    [1, 2, null, 3, 4, null, 5, 1, 3, 2, null, 1, 4],
    fil­ter(iden­tity),
    uniq,
    map(plus(2))),
  [3, 4, 5, 6, 7]);
Parameters:
Name Type Attributes Description
val *

The value to pipe through the func­tions

fns function <repeatable>

Mul­tiple func­tions

Returns:
Type
*

(inner) withFunctionName(name, fn) → {function}

Source:

Manu­ally as­sign a name to a func­tion.

const { stric­tEqual: as­sertIs } = re­quire('assert');
const { with­Func­tion­Name } = re­quire('fer­rum');

const fn = () => {};
as­sertIs(fn.name, 'fn');

const alias = with­Func­tion­Name('foo', fn)
as­sertIs(fn.name, 'foo');
as­sertIs(alias.name, 'foo');
Parameters:
Name Type Description
name String

The new name of the func­tion.

fn function

The func­tion to as­sign a name to

Returns:

The func­tion

Type
function