Tail recursion

Use cases of recursive function with the help of the trampoline namespace.

Further readings

Examples

Range

A simple implementation of a range function.

const { trampoline: {recur, again} } = require('futils');

// rangeRec_ :: ([Number], Number) -> [Number]
const rangeRec_ = recur(function loop (xs, n) {
  return xs[0] <= n
    ? xs
    : again(loop, [xs[0] - 1, ...xs], n);
});

// range :: Number -> Number -> [Number]
const range = start => stop => rangeRec_([stop], start);

range(0)(10); // -> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Unfold

The functional equivalent of a while loop and the opposite of a fold.

const { trampoline: {recur, again} } = require('futils');

// unfoldRec_ :: ((a -> Boolean), (a -> b), a) -> b
const unfoldRec_ = recur(function loop (f, g, init) {
  return f(init)
    ? init
    : again(loop, f, g, g(init));
});

// unfold :: (a -> Boolean) -> (a -> b) -> a -> b
const unfold = predicate => fn => init => unfoldRec_(predicate, fn, init);

Reverse DOM traversal

A polyfill for Element.prototype.closest. Traverses the DOM tree up until the <html> element is hit.

const { trampoline: {recur, again} } = require('futils');

// closestRec_ :: (HTMLElement, String, HTMLElement) -> HTMLElement
const closestRec_ = recur(function loop (stop, selector, node) {
  return !node || node.matches(selector) || node === stop
    ? node
    : again(loop, selector, stop, node.parentNode);
});

// closest :: String -> HTMLElement -> HTMLElement
const closest = selector => node => closestRec_(
  document.documentElement,
  selector,
  node
);