Law of cosines - triples

The Law of cosines states that for an angle g, (gamma) of any triangle, if the sides adjacent to the angle are A and B and the side opposite is C; then the lengths of the sides are related by this formula:
           A2 + B2 - 2ABcos(g) = C2

;Specific angles:
For an angle of of   '''90o'''   this becomes the more familiar "Pythagoras equation":
           A2 + B2  =  C2

For an angle of   '''60o'''   this becomes the less familiar  equation:
           A2 + B2 - AB  =  C2

And finally for an angle of   '''120o'''   this becomes the equation:
           A2 + B2 + AB  =  C2

;Task:
*   Find all integer solutions (in order) to the three specific cases, distinguishing between each angle being considered.
*   Restrain all sides to the integers   '''1..13'''   inclusive.
*   Show how many results there are for each of the three angles mentioned above.
*   Display results on this page.

Note: Triangles with the same length sides but different order are to be treated as the same.

;Optional Extra credit:
* How many 60deg integer triples are there for sides in the range 1..10_000 ''where the sides are not all of the same length''.

;Related Task
* [[Pythagorean triples]]

;See also:
* Visualising Pythagoras: ultimate proofs and crazy contortions Mathlogger Video

Solution:
(() => {
    'use strict';

    // main :: IO ()
    const main = () => {

        const
            f90 = dct => x2 => dct[x2],
            f60 = dct => (x2, ab) => dct[x2 - ab],
            f120 = dct => (x2, ab) => dct[x2 + ab],
            f60unequal = dct => (x2, ab, a, b) =>
            (a !== b) ? (
                dct[x2 - ab]
            ) : undefined;

        // triangles :: Dict -> (Int -> Int -> Int -> Int -> Maybe Int)
        //                   -> [String]
        const triangles = (f, n) => {
            const
                xs = enumFromTo(1, n),
                fr = f(xs.reduce((a, x) => (a[x * x] = x, a), {})),
                gc = xs.reduce((a, _) => a, {}),
                setSoln = new Set();
            return (
                xs.forEach(
                    a => {
                        const a2 = a * a;
                        enumFromTo(1, 1 + a).forEach(
                            b => {
                                const
                                    suma2b2 = a2 + b * b,
                                    c = fr(suma2b2, a * b, a, b);
                                if (undefined !== c) {
                                    setSoln.add([a, b, c].sort())
                                };
                            }
                        );
                    }
                ),
                Array.from(setSoln.keys())
            );
        };

        const
            result = 'Triangles of maximum side 13:\n\n' +
            unlines(
                zipWith(
                    (s, f) => {
                        const ks = triangles(f, 13);
                        return ks.length.toString() + ' solutions for ' + s +
                            ' degrees:\n' + unlines(ks) + '\n';
                    },
                    ['120', '90', '60'],
                    [f120, f90, f60]
                )
            ) + '\nUneven triangles of maximum side 10000. Total:\n' +
            triangles(f60unequal, 10000).length

        return (
            //console.log(result),
            result
        );
    };

    // GENERIC FUNCTIONS ----------------------------

    // concatMap :: (a -> [b]) -> [a] -> [b]
    const concatMap = (f, xs) =>
        xs.reduce((a, x) => a.concat(f(x)), []);

    // enumFromTo :: Int -> Int -> [Int]
    const enumFromTo = (m, n) =>
        m <= n ? iterateUntil(
            x => n <= x,
            x => 1 + x,
            m
        ) : [];

    // iterateUntil :: (a -> Bool) -> (a -> a) -> a -> [a]
    const iterateUntil = (p, f, x) => {
        const vs = [x];
        let h = x;
        while (!p(h))(h = f(h), vs.push(h));
        return vs;
    };

    // Returns Infinity over objects without finite length
    // this enables zip and zipWith to choose the shorter
    // argument when one non-finite like cycle, repeat etc

    // length :: [a] -> Int
    const length = xs => xs.length || Infinity;

    // take :: Int -> [a] -> [a]
    // take :: Int -> String -> String
    const take = (n, xs) =>
        xs.constructor.constructor.name !== 'GeneratorFunction' ? (
            xs.slice(0, n)
        ) : [].concat.apply([], Array.from({
            length: n
        }, () => {
            const x = xs.next();
            return x.done ? [] : [x.value];
        }));

    // unlines :: [String] -> String
    const unlines = xs => xs.join('\n');

    // Use of `take` and `length` here allows zipping with non-finite lists
    // i.e. generators like cycle, repeat, iterate.

    // Use of `take` and `length` here allows zipping with non-finite lists
    // i.e. generators like cycle, repeat, iterate.

    // zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
    const zipWith = (f, xs, ys) => {
        const
            lng = Math.min(length(xs), length(ys)),
            as = take(lng, xs),
            bs = take(lng, ys);
        return Array.from({
            length: lng
        }, (_, i) => f(as[i], bs[i], i));
    };

    // MAIN ---
    return main();
})();


Least common multiple

Compute the   least common multiple   (LCM)   of two integers.

Given   ''m''   and   ''n'',   the least common multiple is the smallest positive integer that has both   ''m''   and   ''n''   as factors.

;Example:
The least common multiple of   '''12'''   and   '''18'''   is   '''36''',       because:
:*   '''12'''   is a factor     ('''12''' x '''3''' = '''36'''),     and
:*   '''18'''   is a factor     ('''18''' x '''2''' = '''36'''),     and
:*   there is no positive integer less than   '''36'''   that has both factors.

As a special case,   if either   ''m''   or   ''n''   is zero,   then the least common multiple is zero.

One way to calculate the least common multiple is to iterate all the multiples of   ''m'',   until you find one that is also a multiple of   ''n''.

If you already have   ''gcd''   for [[greatest common divisor]],   then this formula calculates   ''lcm''.

:::: \operatorname{lcm}(m, n) = \frac{|m \times n|}{\operatorname{gcd}(m, n)}

One can also find   ''lcm''   by merging the [[prime decomposition]]s of both   ''m''   and   ''n''.

;Related task
:*   greatest common divisor.

;See also:
*   MathWorld entry:   Least Common Multiple.
*   Wikipedia entry:   Least common multiple.

Solution:
function LCM(A)  // A is an integer array (e.g. [-50,25,-45,-18,90,447])
{
    var n = A.length, a = Math.abs(A[0]);
    for (var i = 1; i < n; i++)
     { var b = Math.abs(A[i]), c = a;
       while (a && b){ a > b ? a %= b : b %= a; }
       a = Math.abs(c*A[i])/(a+b);
     }
    return a;
}

/* For example:
   LCM([-50,25,-45,-18,90,447]) -> 67050
*/


Least common multiple

Solution:
(() => {
    'use strict';

    // gcd :: Integral a => a -> a -> a
    let gcd = (x, y) => {
        let _gcd = (a, b) => (b === 0 ? a : _gcd(b, a % b)),
            abs = Math.abs;
        return _gcd(abs(x), abs(y));
    }

    // lcm :: Integral a => a -> a -> a
    let lcm = (x, y) =>
        x === 0 || y === 0 ? 0 : Math.abs(Math.floor(x / gcd(x, y)) * y);

    // TEST
    return lcm(12, 18);

})();


Levenshtein distance

{{Wikipedia}}

In information theory and computer science, the '''Levenshtein distance''' is a edit distance). The Levenshtein distance between two strings is defined as the minimum number of edits needed to transform one string into the other, with the allowable edit operations being insertion, deletion, or substitution of a single character.

;Example:
The Levenshtein distance between "'''kitten'''" and "'''sitting'''" is 3, since the following three edits change one into the other, and there isn't a way to do it with fewer than three edits:
::#   '''k'''itten    '''s'''itten       (substitution of 'k' with 's')
::#   sitt'''e'''n    sitt'''i'''n       (substitution of 'e' with 'i')
::#   sittin          sittin'''g'''      (insert 'g' at the end).

''The Levenshtein distance between   "'''rosettacode'''",   "'''raisethysword'''"   is   '''8'''.

''The distance between two strings is same as that when both strings are reversed.''

;Task:
Implements a Levenshtein distance function, or uses a library function, to show the Levenshtein distance between   "kitten"   and   "sitting".

;Related task:
*   [[Longest common subsequence]]

Solution:
function levenshtein(a, b) {
  var t = [], u, i, j, m = a.length, n = b.length;
  if (!m) { return n; }
  if (!n) { return m; }
  for (j = 0; j <= n; j++) { t[j] = j; }
  for (i = 1; i <= m; i++) {
    for (u = [i], j = 1; j <= n; j++) {
      u[j] = a[i - 1] === b[j - 1] ? t[j - 1] : Math.min(t[j - 1], t[j], u[j - 1]) + 1;
    } t = u;
  } return u[n];
}

// tests
[ ['', '', 0],
  ['yo', '', 2],
  ['', 'yo', 2],
  ['yo', 'yo', 0],
  ['tier', 'tor', 2],
  ['saturday', 'sunday', 3],
  ['mist', 'dist', 1],
  ['tier', 'tor', 2],
  ['kitten', 'sitting', 3],
  ['stop', 'tops', 2],
  ['rosettacode', 'raisethysword', 8],
  ['mississippi', 'swiss miss', 8]
].forEach(function(v) {
  var a = v[0], b = v[1], t = v[2], d = levenshtein(a, b);
  if (d !== t) {
    console.log('levenstein("' + a + '","' + b + '") was ' + d + ' should be ' + t);
  }
});


Levenshtein distance

Solution:
(() => {
    'use strict';

    // levenshtein :: String -> String -> Int
    const levenshtein = sa => sb => {
        const cs = chars(sa);
        const go = (ns, c) => {
            const calc = z => tpl => {
                const [c1, x, y] = Array.from(tpl);
                return minimum([
                    succ(y),
                    succ(z),
                    x + (c !== c1 ? 1 : 0)
                ]);
            };
            const [n, ns1] = [ns[0], ns.slice(1)];
            return scanl(calc)(succ(n))(
                zip3(cs)(ns)(ns1)
            );
        };
        return last(
            chars(sb).reduce(
                go,
                enumFromTo(0)(cs.length)
            )
        );
    };

    // ----------------------- TEST ------------------------
    const main = () => [
        ["kitten", "sitting"],
        ["sitting", "kitten"],
        ["rosettacode", "raisethysword"],
        ["raisethysword", "rosettacode"]
    ].map(uncurry(levenshtein));

    // ----------------- GENERIC FUNCTIONS -----------------

    // Tuple (,) :: a -> b -> (a, b)
    const Tuple = a =>
        b => ({
            type: 'Tuple',
            '0': a,
            '1': b,
            length: 2
        });

    // TupleN :: a -> b ...  -> (a, b ... )
    function TupleN() {
        const
            args = Array.from(arguments),
            n = args.length;
        return 2 < n ? Object.assign(
            args.reduce((a, x, i) => Object.assign(a, {
                [i]: x
            }), {
                type: 'Tuple' + n.toString(),
                length: n
            })
        ) : args.reduce((f, x) => f(x), Tuple);
    };

    // chars :: String -> [Char]
    const chars = s =>
        s.split('');

    // enumFromTo :: Int -> Int -> [Int]
    const enumFromTo = m =>
        n => Array.from({
            length: 1 + n - m
        }, (_, i) => m + i);

    // last :: [a] -> a
    const last = xs => (
        // The last item of a list.
        ys => 0 < ys.length ? (
            ys.slice(-1)[0]
        ) : undefined
    )(xs);

    // minimum :: Ord a => [a] -> a
    const minimum = xs => (
        // The least value of xs.
        ys => 0 < ys.length ? (
            ys.slice(1)
            .reduce((a, y) => y < a ? y : a, ys[0])
        ) : undefined
    )(xs);

    // length :: [a] -> Int
    const length = xs =>
        // Returns Infinity over objects without finite
        // length. This enables zip and zipWith to choose
        // the shorter argument when one is non-finite,
        // like cycle, repeat etc
        'GeneratorFunction' !== xs.constructor.constructor.name ? (
            xs.length
        ) : Infinity;

    // scanl :: (b -> a -> b) -> b -> [a] -> [b]
    const scanl = f => startValue => xs =>
        xs.reduce((a, x) => {
            const v = f(a[0])(x);
            return Tuple(v)(a[1].concat(v));
        }, Tuple(startValue)([startValue]))[1];

    // succ :: Enum a => a -> a
    const succ = x =>
        1 + x;

    // uncurry :: (a -> b -> c) -> ((a, b) -> c)
    const uncurry = f =>
        // A function over a pair, derived
        // from a curried function.
        function () {
            const
                args = arguments,
                xy = Boolean(args.length % 2) ? (
                    args[0]
                ) : args;
            return f(xy[0])(xy[1]);
        };

    // zip3 :: [a] -> [b] -> [c] -> [(a, b, c)]
    const zip3 = xs =>
        ys => zs => xs
        .slice(0, Math.min(...[xs, ys, zs].map(length)))
        .map((x, i) => TupleN(x, ys[i], zs[i]));

    // MAIN ---
    return JSON.stringify(main())
})();


List rooted trees

You came back from grocery shopping.    After putting away all the goods, you are left with a pile of plastic bags, which you want to save for later use, so you take one bag and stuff all the others into it, and throw it under the sink.   In doing so, you realize that there are various ways of nesting the bags, with all bags viewed as identical.

If we use a matching pair of parentheses to represent a bag, the ways are:

For 1 bag, there's one way:
  ()	<- a bag

for 2 bags, there's one way:
  (())	<- one bag in another

for 3 bags, there are two:
  ((())) <- 3 bags nested Russian doll style
  (()()) <- 2 bags side by side, inside the third

for 4 bags, four:
  (()()())
  ((())())
  ((()()))
  (((())))

Note that because all bags are identical, the two 4-bag strings ((())()) and (()(())) represent the same configuration.

It's easy to see that each configuration for ''n'' bags represents a ''n''-node rooted tree, where a bag is a tree node, and a bag with its content forms a subtree.  The outermost bag is the tree root.  Number of configurations for given ''n'' is given by OEIS A81.

;Task:
Write a program that, when given ''n'', enumerates all ways of nesting ''n'' bags.   You can use the parentheses notation above, or any tree representation that's unambiguous and preferably intuitive.

This task asks for enumeration of trees only; for counting solutions without enumeration, that OEIS page lists various formulas, but that's not encouraged by this task, especially if implementing it would significantly increase code size.

As an example output, run 5 bags.   There should be 9 ways.

Solution:
(() => {
    'use strict';

    const main = () =>
        bagPatterns(5)
        .join('\n');

    // BAG PATTERNS ---------------------------------------

    // bagPatterns :: Int -> [String]
    const bagPatterns = n =>
        nub(map(
            composeList([
                commasFromTree,
                depthSortedTree,
                treeFromParentIndices
            ]),
            parentIndexPermutations(n)
        ));

    // parentIndexPermutations :: Int -> [[Int]]
    const parentIndexPermutations = n =>
        sequenceA(
            map(curry(enumFromToInt)(0),
                enumFromToInt(0, n - 2)
            )
        );

    // treeFromParentIndices :: [Int] -> Tree Int
    const treeFromParentIndices = pxs => {
        const go = (tree, tplIP) =>
            Node(
                tree.root,
                tree.root === snd(tplIP) ? (
                    tree.nest.concat(Node(fst(tplIP)), [])
                ) : map(t => go(t, tplIP), tree.nest)
            );
        return foldl(
            go, Node(0, []),
            zip(enumFromToInt(1, pxs.length), pxs)
        );
    };

    // Siblings sorted by descendant count

    // depthSortedTree :: Tree a -> Tree Int
    const depthSortedTree = t => {
        const go = tree =>
            isNull(tree.nest) ? (
                Node(0, [])
            ) : (() => {
                const xs = map(go, tree.nest);
                return Node(
                    1 + foldl((a, x) => a + x.root, 0, xs),
                    sortBy(flip(comparing(x => x.root)), xs)
                );
            })();
        return go(t);
    };

    // Serialisation of the tree structure

    // commasFromTree :: Tree a -> String
    const commasFromTree = tree => {
        const go = t => `(${concat(map(go, t.nest))})`
        return go(tree);
    };

    // GENERIC FUNCTIONS --------------------------------------

    // Node :: a -> [Tree a] -> Tree a
    const Node = (v, xs) => ({
        type: 'Node',
        root: v, // any type of value (but must be consistent across tree)
        nest: xs || []
    });

    // Tuple (,) :: a -> b -> (a, b)
    const Tuple = (a, b) => ({
        type: 'Tuple',
        '0': a,
        '1': b,
        length: 2
    });

    // comparing :: (a -> b) -> (a -> a -> Ordering)
    const comparing = f =>
        (x, y) => {
            const
                a = f(x),
                b = f(y);
            return a < b ? -1 : (a > b ? 1 : 0);
        };

    // composeList :: [(a -> a)] -> (a -> a)
    const composeList = fs =>
        x => fs.reduceRight((a, f) => f(a), x, fs);

    // concat :: [[a]] -> [a]
    // concat :: [String] -> String
    const concat = xs =>
        xs.length > 0 ? (() => {
            const unit = typeof xs[0] === 'string' ? '' : [];
            return unit.concat.apply(unit, xs);
        })() : [];

        // concatMap :: (a -> [b]) -> [a] -> [b]
    const concatMap = (f, xs) => []
        .concat.apply(
            [],
            (Array.isArray(xs) ? (
                xs
            ) : xs.split('')).map(f)
        );

        // cons :: a -> [a] -> [a]
    const cons = (x, xs) =>  [x].concat(xs);

    // Flexibly handles two or more arguments, applying
    // the function directly if the argument array is complete,
    // or recursing with a concatenation of any existing and
    // newly supplied arguments, if gaps remain.
    // curry :: ((a, b) -> c) -> a -> b -> c
    const curry = (f, ...args) => {
        const go = xs => xs.length >= f.length ? (
            f.apply(null, xs)
        ) : function() {
            return go(xs.concat(Array.from(arguments)));
        };
        return go(args);
    };

    // enumFromToInt :: Int -> Int -> [Int]
    const enumFromToInt = (m, n) =>
        n >= m ? (
            iterateUntil(x => x >= n, x => 1 + x, m)
        ) : [];

    // flip :: (a -> b -> c) -> b -> a -> c
    const flip = f => (a, b) => f.apply(null, [b, a]);

    // foldl :: (a -> b -> a) -> a -> [b] -> a
    const foldl = (f, a, xs) => xs.reduce(f, a);

    // fst :: (a, b) -> a
    const fst = tpl => tpl[0];

    // isNull :: [a] -> Bool
    // isNull :: String -> Bool
    const isNull = xs =>
        Array.isArray(xs) || typeof xs === 'string' ? (
            xs.length < 1
        ) : undefined;

    // iterateUntil :: (a -> Bool) -> (a -> a) -> a -> [a]
    const iterateUntil = (p, f, x) => {
        let vs = [x],
            h = x;
        while (!p(h))(h = f(h), vs.push(h));
        return vs;
    };

    // liftA2List :: (a -> b -> c) -> [a] -> [b] -> [c]
    const liftA2List = (f, xs, ys) =>
        concatMap(x => concatMap(y => [f(x, y)], ys), xs);

    // map :: (a -> b) -> [a] -> [b]
    const map = (f, xs) => xs.map(f);

    // nub :: [a] -> [a]
    const nub = xs => nubBy((a, b) => a === b, xs);

    // nubBy :: (a -> a -> Bool) -> [a] -> [a]
    const nubBy = (p, xs) => {
        const go = xs => xs.length > 0 ? (() => {
            const x = xs[0];
            return [x].concat(
                go(xs.slice(1)
                    .filter(y => !p(x, y))
                )
            )
        })() : [];
        return go(xs);
    };

    // sequenceA :: (Applicative f, Traversable t) => t (f a) -> f (t a)
    const sequenceA = tfa =>
        traverseList(x => x, tfa);

    // traverseList :: (Applicative f) => (a -> f b) -> [a] -> f [b]
    const traverseList = (f, xs) => {
        const lng = xs.length;
        return 0 < lng ? (() => {
            const
                vLast = f(xs[lng - 1]),
                t = vLast.type || 'List';
            return xs.slice(0, -1).reduceRight(
                (ys, x) => liftA2List(cons, f(x), ys),
                liftA2List(cons, vLast, [[]])
            );
        })() : [
            []
        ];
    };

    // snd :: (a, b) -> b
    const snd = tpl => tpl[1];

    // sortBy :: (a -> a -> Ordering) -> [a] -> [a]
    const sortBy = (f, xs) =>
        xs.slice()
        .sort(f);

    // zip :: [a] -> [b] -> [(a, b)]
    const zip = (xs, ys) =>
        xs.slice(0, Math.min(xs.length, ys.length))
        .map((x, i) => Tuple(x, ys[i]));

    // MAIN ---
    return main()
})();


Long year

Most years have 52 weeks, some have 53, according to ISO8601.

;Task:
Write a function which determines if a given year is long (53 weeks) or not, and demonstrate it.

Solution:
const isLongYear = (year) => {
  const jan1 = new Date(year, 0, 1);
  const dec31 = new Date(year, 11, 31);
  return (4 == jan1.getDay() || 4 == dec31.getDay())
}

for (let y = 1995; y <= 2045; y++) {
  if (isLongYear(y)) {
    console.log(y)
  }
}


Longest common subsequence

'''Introduction'''

Define a ''subsequence'' to be any output string obtained by deleting zero or more symbols from an input string.

The '''Longest Common Subsequence''' ('''LCS''') is a subsequence of maximum length common to two or more strings.

Let ''A''  ''A''[0]... ''A''[m - 1] and ''B''  ''B''[0]... ''B''[n - 1], m < n be strings drawn from an alphabet S of size s, containing every distinct symbol in A + B.

An ordered pair (i, j) will be referred to as a match if ''A''[i] = ''B''[j], where 0 <= i < m and 0 <= j < n.

The set of matches '''M''' defines a relation over matches: '''M'''[i, j] = (i, j)  '''M'''.

Define a ''non-strict'' product-order (<=) over ordered pairs, such that (i1, j1) <= (i2, j2) = i1 <= i2 and j1 <= j2.  We define (>=) similarly.

We say ordered pairs p1 and p2 are ''comparable'' if either p1 <= p2 or p1 >= p2 holds.  If i1 < i2 and j2 < j1 (or i2 < i1 and j1 < j2) then neither p1 <= p2 nor p1 >= p2 are possible, and we say p1 and p2 are ''incomparable''.

Define the ''strict'' product-order (<) over ordered pairs, such that (i1, j1) < (i2, j2) = i1 < i2 and j1 < j2.  We define (>) similarly.

A chain '''C''' is a subset of '''M''' consisting of at least one element m; and where either m1 < m2 or m1 > m2 for every pair of distinct elements m1 and m2.  An antichain '''D''' is any subset of '''M''' in which every pair of distinct elements m1 and m2 are incomparable.

A chain can be visualized as a strictly increasing curve that passes through matches (i, j) in the m*n coordinate space of '''M'''[i, j].

Every Common Sequence of length ''q'' corresponds to a chain of cardinality ''q'', over the set of matches '''M'''.  Thus, finding an LCS can be restated as the problem of finding a chain of maximum cardinality ''p''.

According to [Dilworth 1950], this cardinality ''p'' equals the minimum number of disjoint antichains into which '''M''' can be decomposed.  Note that such a decomposition into the minimal number p of disjoint antichains may not be unique.

'''Background'''

Where the number of symbols appearing in matches is small relative to the length of the input strings, reuse of the symbols increases; and the number of matches will tend towards O(''m*n'') quadratic growth.  This occurs, for example, in the Bioinformatics application of nucleotide and protein sequencing.

The divide-and-conquer approach of [Hirschberg 1975] limits the space required to O(''n'').  However, this approach requires O(''m*n'') time even in the best case.

This quadratic time dependency may become prohibitive, given very long input strings.  Thus, heuristics are often favored over optimal Dynamic Programming solutions.

In the application of comparing file revisions, records from the input files form a large symbol space; and the number of symbols approaches the length of the LCS.  In this case the number of matches reduces to linear, O(''n'') growth.

A binary search optimization due to [Hunt and Szymanski 1977] can be applied to the basic Dynamic Programming approach, resulting in an expected performance of O(''n log m'').  Performance can degrade to O(''m*n log m'') time in the worst case, as the number of matches grows to O(''m*n'').

'''Note'''

[Rick 2000] describes a linear-space algorithm with a time bound of O(''n*s + p*min(m, n - p)'').

'''Legend'''

 A, B are input strings of lengths m, n respectively
 p is the length of the LCS
 M is the set of matches (i, j) such that A[i] = B[j]
 r is the magnitude of M
 s is the magnitude of the alphabet S of distinct symbols in A + B

'''References'''

[Dilworth 1950] "A decomposition theorem for partially ordered sets"
by Robert P. Dilworth, published January 1950,
Annals of Mathematics [Volume 51, Number 1, ''pp.'' 161-166]

[Goeman and Clausen 2002] "A New Practical Linear Space Algorithm for the Longest Common
Subsequence Problem" by Heiko Goeman and Michael Clausen,
published 2002, Kybernetika [Volume 38, Issue 1, ''pp.'' 45-66]

[Hirschberg 1975] "A linear space algorithm for computing maximal common subsequences"
by Daniel S. Hirschberg, published June 1975
Communications of the ACM [Volume 18, Number 6, ''pp.'' 341-343]

[Hunt and McIlroy 1976] "An Algorithm for Differential File Comparison"
by James W. Hunt and M. Douglas McIlroy, June 1976
Computing Science Technical Report, Bell Laboratories 41

[Hunt and Szymanski 1977] "A Fast Algorithm for Computing Longest Common Subsequences"
by James W. Hunt and Thomas G. Szymanski, published May 1977
Communications of the ACM [Volume 20, Number 5, ''pp.'' 350-353]

[Rick 2000] "Simple and fast linear space computation of longest common subsequences"
by Claus Rick, received 17 March 2000, Information Processing Letters,
Elsevier Science [Volume 75, ''pp.'' 275-281]

'''Examples'''

The sequences "1234" and "1224533324" have an LCS of "1234":
 '''1234'''
 '''12'''245'''3'''332'''4'''

For a string example, consider the sequences "thisisatest" and "testing123testing". An LCS would be "tsitest":
 '''t'''hi'''si'''sa'''test'''
 '''t'''e'''s'''t'''i'''ng123'''test'''ing

In this puzzle, your code only needs to deal with strings. Write a function which returns an LCS of two strings (case-sensitive). You don't need to show multiple LCS's.

For more information on this problem please see Wikipedia.

Solution:
function lcs_greedy(x,y){
  var p1, i, idx,
      symbols = {},
      r = 0,
      p = 0,
      l = 0,
      m = x.length,
      n = y.length,
      s = new Buffer((m < n) ? n : m);

  p1 = popsym(0);

  for (i = 0; i < m; i++) {
    p = (r === p) ? p1 : popsym(i);
    p1 = popsym(i + 1);
    if (p > p1) {
      i += 1;
      idx = p1;
    } else {
      idx = p;
    }

    if (idx === n) {
      p = popsym(i);
    } else {
      r = idx;
      s[l] = x.charCodeAt(i);
      l += 1;
    }
  }
  return s.toString('utf8', 0, l);

  function popsym(index) {
    var s = x[index],
        pos = symbols[s] + 1;

    pos = y.indexOf(s, ((pos > r) ? pos : r));
    if (pos === -1) { pos = n; }
    symbols[s] = pos;
    return pos;
  }
}


Longest common substring

Write a function that returns the longest common substring of two strings.

Use it within a program that demonstrates sample output from the function, which will consist of the longest common substring between "thisisatest" and "testing123testing".

Note that substrings are consecutive characters within a string.   This distinguishes them from subsequences, which is any sequence of characters within a string, even if there are extraneous characters in between them.

Hence, the [[longest common subsequence]] between "thisisatest" and "testing123testing" is "tsitest", whereas the longest common sub''string'' is just "test".

;References:
*Generalize Suffix Tree
*[[Ukkonen's Suffix Tree Construction]]

Solution:
(() => {
    'use strict';

    // longestCommon :: String -> String -> String
    const longestCommon = (s1, s2) => maximumBy(
        comparing(length),
        intersect(...apList(
            [s => map(
                concat,
                concatMap(tails, compose(tail, inits)(s))
            )],
            [s1, s2]
        ))
    );

    // main :: IO ()
    const main = () =>
        console.log(
            longestCommon(
                "testing123testing",
                "thisisatest"
            )
        );

    // GENERIC FUNCTIONS ----------------------------

    // Each member of a list of functions applied to each
    // of a list of arguments, deriving a list of new values.

    // apList (<*>) :: [(a -> b)] -> [a] -> [b]
    const apList = (fs, xs) => //
        fs.reduce((a, f) => a.concat(
            xs.reduce((a, x) => a.concat([f(x)]), [])
        ), []);

    // comparing :: (a -> b) -> (a -> a -> Ordering)
    const comparing = f =>
        (x, y) => {
            const
                a = f(x),
                b = f(y);
            return a < b ? -1 : (a > b ? 1 : 0);
        };

    // compose (<<<) :: (b -> c) -> (a -> b) -> a -> c
    const compose = (f, g) => x => f(g(x));

    // concat :: [[a]] -> [a]
    // concat :: [String] -> String
    const concat = xs =>
        0 < xs.length ? (() => {
            const unit = 'string' !== typeof xs[0] ? (
                []
            ) : '';
            return unit.concat.apply(unit, xs);
        })() : [];

    // concatMap :: (a -> [b]) -> [a] -> [b]
    const concatMap = (f, xs) =>
        xs.reduce((a, x) => a.concat(f(x)), []);

    // inits([1, 2, 3]) -> [[], [1], [1, 2], [1, 2, 3]
    // inits('abc') -> ["", "a", "ab", "abc"]

    // inits :: [a] -> [[a]]
    // inits :: String -> [String]
    const inits = xs => [
            []
        ]
        .concat(('string' === typeof xs ? xs.split('') : xs)
            .map((_, i, lst) => lst.slice(0, i + 1)));

    // intersect :: (Eq a) => [a] -> [a] -> [a]
    const intersect = (xs, ys) =>
        xs.filter(x => -1 !== ys.indexOf(x));

    // Returns Infinity over objects without finite length.
    // This enables zip and zipWith to choose the shorter
    // argument when one is non-finite, like cycle, repeat etc

    // length :: [a] -> Int
    const length = xs =>
        (Array.isArray(xs) || 'string' === typeof xs) ? (
            xs.length
        ) : Infinity;

    // map :: (a -> b) -> [a] -> [b]
    const map = (f, xs) => xs.map(f);

    // maximumBy :: (a -> a -> Ordering) -> [a] -> a
    const maximumBy = (f, xs) =>
        0 < xs.length ? (
            xs.slice(1)
            .reduce((a, x) => 0 < f(x, a) ? x : a, xs[0])
        ) : undefined;

    // tail :: [a] -> [a]
    const tail = xs => 0 < xs.length ? xs.slice(1) : [];

    // tails :: [a] -> [[a]]
    const tails = xs => {
        const
            es = ('string' === typeof xs) ? (
                xs.split('')
            ) : xs;
        return es.map((_, i) => es.slice(i))
            .concat([
                []
            ]);
    };

    // MAIN ---
    return main();
})();


Longest increasing subsequence

Calculate and show here a longest increasing subsequence of the list:
:\{3, 2, 6, 4, 5, 1\}
And of the list:
:\{0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15\}

Note that a list may have more than one subsequence that is of the maximum length.

;Ref:
# Dynamic Programming #1: Longest Increasing Subsequence on YouTube
# An efficient solution can be based on Patience sorting.

Solution:
function getLis(input) {
  if (input.length === 0) {
    return [];
  }

  var lisLenPerIndex = [];
  let max = { index: 0, length: 1 };

  for (var i = 0; i < input.length; i++) {
    lisLenPerIndex[i] = 1;
    for (var j = i - 1; j >= 0; j--) {
      if (input[i] > input[j] && lisLenPerIndex[j] >= lisLenPerIndex[i]) {
        var length = lisLenPerIndex[i] = lisLenPerIndex[j] + 1;
        if (length > max.length) {
          max = { index: i, length };
        }
      }
    }
  }

  var lis = [input[max.index]];
  for (var i = max.index; i >= 0 && max.length !== 0; i--) {
    if (input[max.index] > input[i] && lisLenPerIndex[i] === max.length - 1) {
      lis.unshift(input[i]);
      max.length--;
    }
  }

  return lis;
}

console.log(getLongestIncreasingSubsequence([0, 7, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15]));
console.log(getLongestIncreasingSubsequence([3, 2, 6, 4, 5, 1]));


Lucky and even lucky numbers

Note that in the following explanation list indices are assumed to start at ''one''.

;Definition of lucky numbers
''Lucky numbers'' are positive integers that are formed by:

# Form a list of all the positive odd integers > 01, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39 ...
# Return the first number from the list (which is '''1''').
# (Loop begins here)
#* Note then return the second number from the list (which is '''3''').
#* Discard every third, (as noted), number from the list to form the new list1, 3, 7, 9, 13, 15, 19, 21, 25, 27, 31, 33, 37, 39, 43, 45, 49, 51, 55, 57 ...
# (Expanding the loop a few more times...)
#* Note then return the third number from the list (which is '''7''').
#* Discard every 7th, (as noted), number from the list to form the new list1, 3, 7, 9, 13, 15, 21, 25, 27, 31, 33, 37, 43, 45, 49, 51, 55, 57, 63, 67 ...
#* Note then return the 4th number from the list (which is '''9''').
#* Discard every 9th, (as noted), number from the list to form the new list1, 3, 7, 9, 13, 15, 21, 25, 31, 33, 37, 43, 45, 49, 51, 55, 63, 67, 69, 73 ...
#* Take the 5th, i.e. '''13'''.  Remove every 13th.
#* Take the 6th, i.e. '''15'''.  Remove every 15th.
#* Take the 7th, i.e. '''21'''.  Remove every 21th.
#* Take the 8th, i.e. '''25'''.  Remove every 25th.
# (Rule for the loop)
#* Note the nth, which is m.
#* Remove every mth.
#* Increment n.

;Definition of even lucky numbers
This follows the same rules as the definition of lucky numbers above ''except for the very first step'':
# Form a list of all the positive '''even''' integers > 02, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40 ...
# Return the first number from the list (which is '''2''').
# (Loop begins here)
#* Note then return the second number from the list (which is '''4''').
#* Discard every 4th, (as noted), number from the list to form the new list2, 4, 6, 10, 12, 14, 18, 20, 22, 26, 28, 30, 34, 36, 38, 42, 44, 46, 50, 52 ...
# (Expanding the loop a few more times...)
#* Note then return the third number from the list (which is '''6''').
#* Discard every 6th, (as noted), number from the list to form the new list2, 4, 6, 10, 12, 18, 20, 22, 26, 28, 34, 36, 38, 42, 44, 50, 52, 54, 58, 60 ...
#* Take the 4th, i.e. '''10'''.  Remove every 10th.
#* Take the 5th, i.e. '''12'''.  Remove every 12th.
# (Rule for the loop)
#* Note the nth, which is m.
#* Remove every mth.
#* Increment n.

;Task requirements
* Write one or two subroutines (functions) to generate ''lucky numbers'' and ''even lucky numbers''
* Write a command-line interface to allow selection of which kind of numbers and which number(s). Since input is from the command line, tests should be made for the common errors:
** missing arguments
** too many arguments
** number (or numbers) aren't legal
** misspelled argument ('''lucky''' or '''evenLucky''')
* The command line handling should:
** support mixed case handling of the (non-numeric) arguments
** support printing a particular number
** support printing a range of numbers by their index
** support printing a range of numbers by their values
* The resulting list of numbers should be printed on a single line.

The program should support the arguments:

                             what is displayed  (on a single line)
       argument(s)              (optional verbiage is encouraged)
  +-------------------+----------------------------------------------------+
  |  j                |  Jth       lucky number                            |
  |  j  ,      lucky  |  Jth       lucky number                            |
  |  j  ,  evenLucky  |  Jth  even lucky number                            |
  |                   |                                                    |
  |  j  k             |  Jth  through  Kth (inclusive)       lucky numbers |
  |  j  k      lucky  |  Jth  through  Kth (inclusive)       lucky numbers |
  |  j  k  evenLucky  |  Jth  through  Kth (inclusive)  even lucky numbers |
  |                   |                                                    |
  |  j -k             |  all       lucky numbers in the range  j --> |k|   |
  |  j -k      lucky  |  all       lucky numbers in the range  j --> |k|   |
  |  j -k  evenLucky  |  all  even lucky numbers in the range  j --> |k|   |
  +-------------------+----------------------------------------------------+
                           where    |k|    is the absolute value of   k

Demonstrate the program by:
* showing the first twenty ''lucky'' numbers
* showing the first twenty ''even lucky'' numbers
* showing all ''lucky'' numbers between 6,000 and 6,100 (inclusive)
* showing all ''even lucky'' numbers in the same range as above
* showing the 10,000th ''lucky'' number (extra credit)
* showing the 10,000th ''even lucky'' number (extra credit)

;See also:
* This task is related to the [[Sieve of Eratosthenes]] task.
* OEIS Wiki Lucky numbers.
* Sequence A000959 lucky numbers on The On-Line Encyclopedia of Integer Sequences.
* Sequence A045954 even lucky numbers or ELN on The On-Line Encyclopedia of Integer Sequences.
* Entry lucky numbers on The Eric Weisstein's World of Mathematics.

Solution:
function luckyNumbers(opts={}) {
  /**************************************************************************\
  | OPTIONS                                                                  |
  |**************************************************************************|
  |   even ...... boolean ............. return even/uneven numbers           |
  |                                     (default: false)                     |
  |                                                                          |
  |   nth ....... number ............... return nth number                   |
  |                                                                          |
  |   through ... number ............... return numbers from #1 to number    |
  |               OR array[from, to] ... return numbers on index             |
  |                                      from array[from] to array[to]       |
  |                                                                          |
  |   range ..... array[from, to] ...... return numbers between from and to  |
  \**************************************************************************/

  opts.even =  opts.even || false;
  if (typeof opts.through == 'number') opts.through = [0, opts.through];
  let out = [],
      x = opts.even ? 2 : 1,
      max = opts.range ? opts.range[1] * 3
        : opts.through ? opts.through[1] * 12
        : opts.nth ? opts.nth * 15
        : 2000;

  for (x; x <= max; x = x+2) out.push(x);            // fill
  for (x = 1; x < Math.floor(out.length / 2); x++) { // sieve
    let i = out.length;
    while (i--)
      (i+1) % out[x] == 0 && out.splice(i, 1);
  }

  if (opts.nth) return out[opts.nth-1];
  if (opts.through) return out.slice(opts.through[0], opts.through[1]);
  if (opts.range) return out.filter(function(val) {
      return val >= opts.range[0] && val <= opts.range[1];
    });
  return out;
}

/* TESTING */
// blank
console.log( luckyNumbers() );
// showing the first twenty lucky numbers
console.log( luckyNumbers({through: 20}) );
// showing the first twenty even lucky numbers
console.log( luckyNumbers({even: true, through: 20}) );
// showing all lucky numbers between 6,000 and 6,100 (inclusive)
console.log( luckyNumbers({range: [6000, 6100]}) );
// showing all even lucky numbers in the same range as above
console.log( luckyNumbers({even: true, range: [6000, 6100]}) );
// showing the 10,000th lucky number (extra credit)
console.log( luckyNumbers({nth: 10000}) );
// showing the 10,000th even lucky number (extra credit)
console.log( luckyNumbers({even: true, nth: 10000}) );


MAC vendor lookup

Every connected device around the world comes with a unique Media Access Control address, or a   MAC address.

A common task a network administrator may come across is being able to identify a network device's manufacturer when given only a MAC address.

;Task:
Interface with one (or numerous) APIs that exist on the internet and retrieve the device manufacturer based on a supplied MAC address.

A MAC address that does not return a valid result should return the String "N/A".   An error related to the network connectivity or the API should return a null result.

Many implementations on this page use http://api.macvendors.com/ which, as of 19th September 2021, is throttling requests. After only 2 calls, the following response is returned for all subsequent requests. If you are planning to use the same provider or going to run the examples on this page, consider building in a delay between two calls.

'''{"errors":{"detail":"Too Many Requests","message":"Please slow down your requests or upgrade your plan at https://macvendors.com"}}'''

Solution:
var mac = "88:53:2E:67:07:BE";
function findmac(){
	window.open("http://api.macvendors.com/" + mac);
}

findmac();


MD4

Find the MD4 message digest of a string of [[octet]]s.
Use the ASCII encoded string "Rosetta Code" (without quotes).
You may either call an MD4 library, or implement MD4 in your language.

'''MD4''' is an obsolete hash function that computes a 128-bit message digest that sometimes appears in obsolete protocols.

RFC 1320 specifies the MD4 algorithm. RFC 6150 declares that MD4 is obsolete.

Solution:
const md4func = () => {

  const hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase    */
  const b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance  */
  const chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode   */

  const tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  const hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";

  /**
   * Add integers, wrapping at 2^32. This uses 16-bit operations internally
   * to work around bugs in some JS interpreters.
   */
  const safe_add = (x, y) => {
    const lsw = (x & 0xFFFF) + (y & 0xFFFF);
    const msw = (x >> 16) + (y >> 16) + (lsw >> 16);
    return (msw << 16) | (lsw & 0xFFFF);
  };

  /**
   * Bitwise rotate a 32-bit number to the left.
   */
  const rol = (num, cnt) => (num << cnt) | (num >>> (32 - cnt));

  /**
   * Convert a string to an array of little-endian words
   * If chrsz is ASCII, characters >255 have their hi-byte silently ignored.
   */
  const str2binl = str => {
    const bin = Array();
    const mask = (1 << chrsz) - 1;
    for (let i = 0; i < str.length * chrsz; i += chrsz)
      bin[i >> 5] |= (str.charCodeAt(i / chrsz) & mask) << (i % 32);
    return bin;
  };

  /**
   * Convert an array of little-endian words to a string
   */
  const binl2str = bin => {
    let str = "";
    const mask = (1 << chrsz) - 1;
    for (let i = 0; i < bin.length * 32; i += chrsz)
      str += String.fromCharCode((bin[i >> 5] >>> (i % 32)) & mask);
    return str;
  };

  /**
   * Convert an array of little-endian words to a hex string.
   */
  const binl2hex = binarray => {
    let str = "";
    for (let i = 0; i < binarray.length * 4; i++) {
      str += hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8 + 4)) & 0xF) +
          hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8)) & 0xF);
    }
    return str;
  };

  /**
   * Convert an array of little-endian words to a base-64 string
   */
  const binl2b64 = binarray => {
    let str = "";
    for (let i = 0; i < binarray.length * 4; i += 3) {
      const triplet = (((binarray[i >> 2] >> 8 * (i % 4)) & 0xFF) << 16)
          | (((binarray[i + 1 >> 2] >> 8 * ((i + 1) % 4)) & 0xFF) << 8)
          | ((binarray[i + 2 >> 2] >> 8 * ((i + 2) % 4)) & 0xFF);
      for (let j = 0; j < 4; j++) {
        if (i * 8 + j * 6 > binarray.length * 32) str += b64pad;
        else str += tab.charAt((triplet >> 6 * (3 - j)) & 0x3F);
      }
    }
    return str;
  };

  /**
   * Calculate the MD4 of an array of little-endian words, and a bit length
   */
  const core_md4 = (x, len) => {

    x[len >> 5] |= 0x80 << (len % 32);
    x[(((len + 64) >>> 9) << 4) + 14] = len;
    let a = 1732584193;
    let b = -271733879;
    let c = -1732584194;
    let d = 271733878;

    for (let i = 0; i < x.length; i += 16) {

      const olda = a;
      const oldb = b;
      const oldc = c;
      const oldd = d;

      a = md4_ff(a, b, c, d, x[i], 3);
      d = md4_ff(d, a, b, c, x[i + 1], 7);
      c = md4_ff(c, d, a, b, x[i + 2], 11);
      b = md4_ff(b, c, d, a, x[i + 3], 19);
      a = md4_ff(a, b, c, d, x[i + 4], 3);
      d = md4_ff(d, a, b, c, x[i + 5], 7);
      c = md4_ff(c, d, a, b, x[i + 6], 11);
      b = md4_ff(b, c, d, a, x[i + 7], 19);
      a = md4_ff(a, b, c, d, x[i + 8], 3);
      d = md4_ff(d, a, b, c, x[i + 9], 7);
      c = md4_ff(c, d, a, b, x[i + 10], 11);
      b = md4_ff(b, c, d, a, x[i + 11], 19);
      a = md4_ff(a, b, c, d, x[i + 12], 3);
      d = md4_ff(d, a, b, c, x[i + 13], 7);
      c = md4_ff(c, d, a, b, x[i + 14], 11);
      b = md4_ff(b, c, d, a, x[i + 15], 19);

      a = md4_gg(a, b, c, d, x[i], 3);
      d = md4_gg(d, a, b, c, x[i + 4], 5);
      c = md4_gg(c, d, a, b, x[i + 8], 9);
      b = md4_gg(b, c, d, a, x[i + 12], 13);
      a = md4_gg(a, b, c, d, x[i + 1], 3);
      d = md4_gg(d, a, b, c, x[i + 5], 5);
      c = md4_gg(c, d, a, b, x[i + 9], 9);
      b = md4_gg(b, c, d, a, x[i + 13], 13);
      a = md4_gg(a, b, c, d, x[i + 2], 3);
      d = md4_gg(d, a, b, c, x[i + 6], 5);
      c = md4_gg(c, d, a, b, x[i + 10], 9);
      b = md4_gg(b, c, d, a, x[i + 14], 13);
      a = md4_gg(a, b, c, d, x[i + 3], 3);
      d = md4_gg(d, a, b, c, x[i + 7], 5);
      c = md4_gg(c, d, a, b, x[i + 11], 9);
      b = md4_gg(b, c, d, a, x[i + 15], 13);

      a = md4_hh(a, b, c, d, x[i], 3);
      d = md4_hh(d, a, b, c, x[i + 8], 9);
      c = md4_hh(c, d, a, b, x[i + 4], 11);
      b = md4_hh(b, c, d, a, x[i + 12], 15);
      a = md4_hh(a, b, c, d, x[i + 2], 3);
      d = md4_hh(d, a, b, c, x[i + 10], 9);
      c = md4_hh(c, d, a, b, x[i + 6], 11);
      b = md4_hh(b, c, d, a, x[i + 14], 15);
      a = md4_hh(a, b, c, d, x[i + 1], 3);
      d = md4_hh(d, a, b, c, x[i + 9], 9);
      c = md4_hh(c, d, a, b, x[i + 5], 11);
      b = md4_hh(b, c, d, a, x[i + 13], 15);
      a = md4_hh(a, b, c, d, x[i + 3], 3);
      d = md4_hh(d, a, b, c, x[i + 11], 9);
      c = md4_hh(c, d, a, b, x[i + 7], 11);
      b = md4_hh(b, c, d, a, x[i + 15], 15);

      a = safe_add(a, olda);
      b = safe_add(b, oldb);
      c = safe_add(c, oldc);
      d = safe_add(d, oldd);
    }

    return Array(a, b, c, d);

  };

  /**
   * These functions implement the basic operation for each round of the
   * algorithm.
   */
  const md4_cmn = (q, a, b, x, s, t) => safe_add(
      rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b);

  const md4_ff = (a, b, c, d, x, s) => md4_cmn(
      (b & c) | ((~b) & d), a, 0, x, s, 0);

  const md4_gg = (a, b, c, d, x, s) => md4_cmn(
      (b & c) | (b & d) | (c & d), a, 0, x, s, 1518500249);

  const md4_hh = (a, b, c, d, x, s) => md4_cmn(
      b ^ c ^ d, a, 0, x, s, 1859775393);

  /**
   * Calculate the HMAC-MD4, of a key and some data
   */
  const core_hmac_md4 = (key, data) => {

    let bkey = str2binl(key);
    if (bkey.length > 16) {
      bkey = core_md4(bkey, key.length * chrsz)
    }

    const ipad = Array(16);
    const opad = Array(16);

    for (let i = 0; i < 16; i++) {
      ipad[i] = bkey[i] ^ 0x36363636;
      opad[i] = bkey[i] ^ 0x5C5C5C5C;
    }
    const hash = core_md4(
        ipad.concat(str2binl(data)), 512 + data.length * chrsz);

    return core_md4(opad.concat(hash), 512 + 128);
  };

  /**
   * These are the functions you'll usually want to call
   */
  return {
    hex_md4: s => binl2hex(core_md4(str2binl(s), s.length * chrsz)),
    b64_md4: s => binl2b64(core_md4(str2binl(s), s.length * chrsz)),
    str_md4: s => binl2str(core_md4(str2binl(s), s.length * chrsz)),
    hex_hmac_md4: (key, data) => binl2hex(core_hmac_md4(key, data)),
    b64_hmac_md4: (key, data) => binl2b64(core_hmac_md4(key, data)),
    str_hmac_md4: (key, data) => binl2str(core_hmac_md4(key, data)),
  };

};

const md4 = md4func();
console.log(md4.hex_md4('Rosetta Code'));


Magic 8-ball

Create Magic 8-Ball.

See details at:   Magic 8-Ball.

Solution:
//console
var answers = [ "It is certain", "It is decidedly so", "Without a doubt",
        "Yes, definitely", "You may rely on it", "As I see it, yes",
        "Most likely", "Outlook good", "Signs point to yes", "Yes",
        "Reply hazy, try again", "Ask again later",
        "Better not tell you now", "Cannot predict now",
        "Concentrate and ask again", "Don't bet on it",
        "My reply is no", "My sources say no", "Outlook not so good",
        "Very doubtful"])

console.log("ASK ANY QUESTION TO THE MAGIC 8-BALL AND YOU SHALL RECEIVE AN ANSWER!")

for(;;){
  var answer = prompt("question:")
  console.log(answer)
console.log(answers[Math.floor(Math.random()*answers.length)]);
}


Magic squares of doubly even order

Solution:
(() => {
    'use strict';

    // doublyEvenMagicSquare :: Int -> [[Int]]
    const doublyEvenMagicSquare = n =>
        0 === n % 4 ? (() => {
            const
                sqr = n * n,
                power = Math.log2(sqr),
                scale = replicate(n / 4);
            return chunksOf(n)(
                map((x, i) => x ? 1 + i : sqr - i)(
                    isInt(power) ? truthSeries(power) : (
                        compose(
                            flatten,
                            scale,
                            map(scale),
                            chunksOf(4)
                        )(truthSeries(4))
                    )
                )
            );
        })() : undefined;

    // truthSeries :: Int -> [Bool]
    const truthSeries = n =>
        0 >= n ? (
            [true]
        ) : (() => {
            const xs = truthSeries(n - 1);
            return xs.concat(xs.map(x => !x));
        })();

    // TEST -----------------------------------------------
    const main = () =>
        // Magic squares of orders 4, 8 and 12, with
        // checks of row, column and diagonal sums.
        intercalate('\n\n')(
            map(n => {
                const
                    lines = doublyEvenMagicSquare(n),
                    sums = map(sum)(
                        lines.concat(
                            transpose(lines)
                            .concat(diagonals(lines))
                        )
                    ),
                    total = sums[0];
                return unlines([
                    "Order: " + str(n),
                    "Summing to: " + str(total),
                    "Row, column and diagonal sums checked: " +
                    str(all(eq(total))(sums)) + '\n',
                    unlines(map(compose(
                        intercalate('  '),
                        map(compose(justifyRight(3)(' '), str))
                    ))(lines))
                ]);
            })([4, 8, 12])
        );

    // GENERIC FUNCTIONS ----------------------------------

    // all :: (a -> Bool) -> [a] -> Bool
    const all = p =>
        // True if p(x) holds for every x in xs.
        xs => xs.every(p);

    // chunksOf :: Int -> [a] -> [[a]]
    const chunksOf = n => xs =>
        enumFromThenTo(0)(n)(
            xs.length - 1
        ).reduce(
            (a, i) => a.concat([xs.slice(i, (n + i))]),
            []
        );

    // compose (<<<) :: (b -> c) -> (a -> b) -> a -> c
    const compose = (...fs) =>
        x => fs.reduceRight((a, f) => f(a), x);

    // diagonals :: [[a]] -> [[a], [a]]
    const diagonals = rows =>
        // Two diagonal sequences,
        // from top left and bottom left
        // respectively, of a given matrix.
        map(flip(zipWith(index))(
            enumFromTo(0)(pred(
                0 < rows.length ? (
                    rows[0].length
                ) : 0
            ))
        ))([rows, reverse(rows)]);

    // enumFromThenTo :: Int -> Int -> Int -> [Int]
    const enumFromThenTo = x1 => x2 => y => {
        const d = x2 - x1;
        return Array.from({
            length: Math.floor(y - x2) / d + 2
        }, (_, i) => x1 + (d * i));
    };

    // enumFromTo :: Int -> Int -> [Int]
    const enumFromTo = m => n =>
        Array.from({
            length: 1 + n - m
        }, (_, i) => m + i);

    // eq (==) :: Eq a => a -> a -> Bool
    const eq = a => b => a === b;

    // flatten :: NestedList a -> [a]
    const flatten = nest => nest.flat(Infinity);

    // flip :: (a -> b -> c) -> b -> a -> c
    const flip = f =>
        x => y => f(y)(x);

    // index (!!) :: [a] -> Int -> a
    const index = xs => i => xs[i];

    // intercalate :: String -> [String] -> String
    const intercalate = s =>
        xs => xs.join(s);

    // isInt :: Int -> Bool
    const isInt = x => x === Math.floor(x);

    // justifyRight :: Int -> Char -> String -> String
    const justifyRight = n => cFiller => s =>
        n > s.length ? (
            s.padStart(n, cFiller)
        ) : s;

    // map :: (a -> b) -> [a] -> [b]
    const map = f => xs =>
        (Array.isArray(xs) ? (
            xs
        ) : xs.split('')).map(f);

    // pred :: Enum a => a -> a
    const pred = x => x - 1;

    // replicate :: Int -> a -> [a]
    const replicate = n => x =>
        Array.from({
            length: n
        }, () => x);

    // reverse :: [a] -> [a]
    const reverse = xs =>
        'string' !== typeof xs ? (
            xs.slice(0).reverse()
        ) : xs.split('').reverse().join('');

    // show :: a -> String
    const show = x => JSON.stringify(x);

    // str :: a -> String
    const str = x => x.toString();

    // sum :: [Num] -> Num
    const sum = xs => xs.reduce((a, x) => a + x, 0);

    // transpose :: [[a]] -> [[a]]
    const transpose = xs =>
        xs[0].map((_, iCol) => xs.map((row) => row[iCol]));

    // unlines :: [String] -> String
    const unlines = xs => xs.join('\n');

    // zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
    const zipWith = f => xs => ys =>
        xs.slice(
            0, Math.min(xs.length, ys.length)
        ).map((x, i) => f(x)(ys[i]));

    // MAIN ------------------------------------------------
    return main();
})();


Magic squares of odd order

A magic square is an   '''NxN'''   square matrix whose numbers (usually integers) consist of consecutive numbers arranged so that the sum of each row and column,   ''and''   both long (main) diagonals are equal to the same sum (which is called the   ''magic number''   or   ''magic constant'').

The numbers are usually (but not always) the first   '''N'''2   positive integers.

A magic square whose rows and columns add up to a magic number but whose main diagonals do not, is known as a ''semimagic square''.

{| class="wikitable" style="float:right;border: 4px solid blue; background:lightgreen; color:black; margin-left:auto;margin-right:auto;text-align:center;width:15em;height:15em;table-layout:fixed;font-size:150%"
|-
| '''8''' || '''1''' || '''6'''
|-
| '''3''' || '''5''' || '''7'''
|-
| '''4''' || '''9''' || '''2'''
|}

;Task
For any odd   '''N''',   generate a magic square with the integers   ''' 1''' --> '''N''',   and show the results here.

Optionally, show the ''magic number''.

You should demonstrate the generator by showing at least a magic square for   '''N''' = '''5'''.

; Related tasks
* [[Magic squares of singly even order]]
* [[Magic squares of doubly even order]]

; See also:
* MathWorld(tm) entry: Magic_square
* Odd Magic Squares (1728.org)

Solution:
(function () {

  // n -> [[n]]
  function magic(n) {
    return n % 2 ? rotation(
      transposed(
        rotation(
          table(n)
        )
      )
    ) : null;
  }

  // [[a]] -> [[a]]
  function rotation(lst) {
    return lst.map(function (row, i) {
      return rotated(
        row, ((row.length + 1) / 2) - (i + 1)
      );
    })
  }

  // [[a]] -> [[a]]
  function transposed(lst) {
    return lst[0].map(function (col, i) {
      return lst.map(function (row) {
        return row[i];
      })
    });
  }

  // [a] -> n -> [a]
  function rotated(lst, n) {
    var lng = lst.length,
      m = (typeof n === 'undefined') ? 1 : (
        n < 0 ? lng + n : (n > lng ? n % lng : n)
      );

    return m ? (
      lst.slice(-m).concat(lst.slice(0, lng - m))
    ) : lst;
  }

  // n -> [[n]]
  function table(n) {
    var rngTop = rng(1, n);

    return rng(0, n - 1).map(function (row) {
      return rngTop.map(function (x) {
        return row * n + x;
      });
    });
  }

  // [m..n]
  function rng(m, n) {
    return Array.apply(null, Array(n - m + 1)).map(
      function (x, i) {
        return m + i;
      });
  }

  /******************** TEST WITH 3, 5, 11 ***************************/

  // Results as right-aligned wiki tables
  function wikiTable(lstRows, blnHeaderRow, strStyle) {
    var css = strStyle ? 'style="' + strStyle + '"' : '';

    return '{| class="wikitable" ' + css + lstRows.map(
      function (lstRow, iRow) {
        var strDelim = ((blnHeaderRow && !iRow) ? '!' : '|'),
          strDbl = strDelim + strDelim;

        return '\n|-\n' + strDelim + ' ' + lstRow.join(' ' + strDbl + ' ');
      }).join('') + '\n|}';
  }

  return [3, 5, 11].map(
    function (n) {
      var w = 2.5 * n;
      return 'magic(' + n + ')\n\n' + wikiTable(
        magic(n), false, 'text-align:center;width:' + w + 'em;height:' + w + 'em;table-layout:fixed;'
      )
    }
  ).join('\n\n')
})();


Magic squares of odd order

Solution:
(() => {

    // Number of rows -> n rows of integers
    // oddMagicTable :: Int -> [[Int]]
    const oddMagicTable = n =>
        mapAsTable(n, siamMap(quot(n, 2)));

    // Highest index of square -> Siam xys so far -> xy -> next xy coordinate
    // nextSiam :: Int -> M.Map (Int, Int) Int -> (Int, Int) -> (Int, Int)
    const nextSiam = (uBound, sMap, [x, y]) => {
        const [a, b] = [x + 1, y - 1];
        return (a > uBound && b < 0) ? (
                [uBound, 1]             // Move down if obstructed by corner
            ) : a > uBound ? (
                [0, b]                  // Wrap at right edge
            ) : b < 0 ? (
                [a, uBound]             // Wrap at upper edge
            ) : mapLookup(sMap, [a, b])
            .nothing ? (                // Unimpeded default: one up one right
                [a, b]
            ) : [a - 1, b + 2];         // Position occupied: move down
    };

    // Order of table -> Siamese indices keyed by coordinates
    // siamMap :: Int -> M.Map (Int, Int) Int
    const siamMap = n => {
        const
            uBound = 2 * n,
            sPath = (uBound, sMap, xy, n) => {
                const [x, y] = xy,
                newMap = mapInsert(sMap, xy, n);
                return (y == uBound && x == quot(uBound, 2) ? (
                    newMap
                ) : sPath(
                    uBound, newMap, nextSiam(uBound, newMap, [x, y]), n + 1));
            };
        return sPath(uBound, {}, [n, 0], 1);
    };

    // Size of square -> integers keyed by coordinates -> rows of integers
    // mapAsTable :: Int -> M.Map (Int, Int) Int -> [[Int]]
    const mapAsTable = (nCols, dct) => {
        const axis = enumFromTo(0, nCols - 1);
        return map(row => map(k => fromJust(mapLookup(dct, k)), row),
            bind(axis, y => [bind(axis, x => [
                [x, y]
            ])]));
    };

    // GENERIC FUNCTIONS ------------------------------------------------------

    // bind :: [a] -> (a -> [b]) -> [b]
    const bind = (xs, f) => [].concat.apply([], xs.map(f));

    // curry :: Function -> Function
    const curry = (f, ...args) => {
        const go = xs => xs.length >= f.length ? (f.apply(null, xs)) :
            function () {
                return go(xs.concat(Array.from(arguments)));
            };
        return go([].slice.call(args, 1));
    };

    // enumFromTo :: Int -> Int -> [Int]
    const enumFromTo = (m, n) =>
        Array.from({
            length: Math.floor(n - m) + 1
        }, (_, i) => m + i);

    // fromJust :: M a -> a
    const fromJust = m => m.nothing ? {} : m.just;

    // fst :: [a, b] -> a
    const fst = pair => pair.length === 2 ? pair[0] : undefined;

    // intercalate :: String -> [a] -> String
    const intercalate = (s, xs) => xs.join(s);

    // justifyRight :: Int -> Char -> Text -> Text
    const justifyRight = (n, cFiller, strText) =>
        n > strText.length ? (
            (cFiller.repeat(n) + strText)
            .slice(-n)
        ) : strText;

    // length :: [a] -> Int
    const length = xs => xs.length;

    // log :: a -> IO ()
    const log = (...args) =>
        console.log(
            args
            .map(show)
            .join(' -> ')
        );

    // map :: (a -> b) -> [a] -> [b]
    const map = (f, xs) => xs.map(f);

    // mapInsert :: Dictionary -> k -> v -> Dictionary
    const mapInsert = (dct, k, v) =>
        (dct[(typeof k === 'string' && k) || show(k)] = v, dct);

    // mapKeys :: Map k a -> [k]
    const mapKeys = dct =>
        sortBy(mappendComparing([snd, fst]),
            map(JSON.parse, Object.keys(dct)));

    // mapLookup :: Dictionary -> k -> Maybe v
    const mapLookup = (dct, k) => {
        const
            v = dct[(typeof k === 'string' && k) || show(k)],
            blnJust = (typeof v !== 'undefined');
        return {
            nothing: !blnJust,
            just: v
        };
    };

    // mappendComparing :: [(a -> b)] -> (a -> a -> Ordering)
    const mappendComparing = fs => (x, y) =>
        fs.reduce((ord, f) => {
            if (ord !== 0) return ord;
            const
                a = f(x),
                b = f(y);
            return a < b ? -1 : a > b ? 1 : 0
        }, 0);

    // maximum :: [a] -> a
    const maximum = xs =>
        xs.reduce((a, x) => (x > a || a === undefined ? x : a), undefined);

    // Integral a => a -> a -> a
    const quot = (n, m) => Math.floor(n / m);

    // show :: a -> String
    const show = x => JSON.stringify(x);
    //
    // snd :: (a, b) -> b
    const snd = tpl => Array.isArray(tpl) ? tpl[1] : undefined;
    //
    // sortBy :: (a -> a -> Ordering) -> [a] -> [a]
    const sortBy = (f, xs) => xs.slice()
        .sort(f);

    // table :: String -> [[String]] -> [String]
    const table = (delim, rows) =>
        map(curry(intercalate)(delim),
            transpose(map(col =>
                map(curry(justifyRight)(maximum(map(length, col)))(' '), col),
                transpose(rows))));

    // transpose :: [[a]] -> [[a]]
    const transpose = xs =>
        xs[0].map((_, col) => xs.map(row => row[col]));

    // unlines :: [String] -> String
    const unlines = xs => xs.join('\n');

    // TEST -------------------------------------------------------------------

    return intercalate('\n\n',
        bind([3, 5, 7],
            n => unlines(table("  ",
                map(xs => map(show, xs), oddMagicTable(n))))));
})();


Map range

Given two ranges:
:::*   [a_1,a_2]   and
:::*   [b_1,b_2];
:::*   then a value   s   in range   [a_1,a_2]
:::*   is linearly mapped to a value   t   in range   [b_1,b_2]
   where:

:::*   t = b_1 + {(s - a_1)(b_2 - b_1) \over (a_2 - a_1)}

;Task:
Write a function/subroutine/... that takes two ranges and a real number, and returns the mapping of the real number from the first to the second range.

Use this function to map values from the range    [0, 10]    to the range    [-1, 0].

;Extra credit:
Show additional idiomatic ways of performing the mapping, using tools available to the language.

Solution:
// Javascript doesn't have built-in support for ranges
// Insted we use arrays of two elements to represent ranges
var mapRange = function(from, to, s) {
  return to[0] + (s - from[0]) * (to[1] - to[0]) / (from[1] - from[0]);
};

var range = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
for (var i = 0; i < range.length; i++) {
  range[i] = mapRange([0, 10], [-1, 0], range[i]);
}

console.log(range);


Matrix digital rain

Implement the Matrix Digital Rain visual effect from the movie "The Matrix" as described in Wikipedia.

Provided is a reference implementation in Common Lisp to be run in a terminal.

Solution:
var tileSize = 20;
// a higher fade factor will make the characters fade quicker
var fadeFactor = 0.05;

var canvas;
var ctx;

var columns = [];
var maxStackHeight;

function init() {
	canvas = document.getElementById('canvas');
	ctx = canvas.getContext('2d');

    // https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver
    const resizeObserver = new ResizeObserver(entries =>
    {
        for (let entry of entries)
        {
            if (entry.contentBoxSize)
            {
                // Firefox implements `contentBoxSize` as a single content rect, rather than an array
                const contentBoxSize = Array.isArray(entry.contentBoxSize) ? entry.contentBoxSize[0] : entry.contentBoxSize;

                canvas.width = contentBoxSize.inlineSize;
                canvas.height = window.innerHeight;

                initMatrix();
            }
        }
    });

    // observe the size of the document
    resizeObserver.observe(document.documentElement);

	// start the main loop
	tick();
}

function initMatrix() {
    columns = [];

    maxStackHeight = Math.ceil(canvas.height/tileSize);

    // divide the canvas into columns
    for (let i = 0 ; i < canvas.width/tileSize ; ++i) {
        var column = {};
        // save the x position of the column
        column.x = i*tileSize;
        // create a random stack height for the column
        column.stackHeight = 10+Math.random()*maxStackHeight;
        // add a counter to count the stack height
        column.stackCounter = 0;
        // add the column to the list
        columns.push(column);
    }
}

function draw() {
    // draw a semi transparent black rectangle on top of the scene to slowly fade older characters
    ctx.fillStyle = "rgba(0 , 0 , 0 , "+fadeFactor+")";
    ctx.fillRect(0 , 0 , canvas.width , canvas.height);

    ctx.font = (tileSize-2)+"px monospace";
    ctx.fillStyle = "rgb(0 , 255 , 0)";
    for (let i = 0 ; i < columns.length ; ++i) {
        // pick a random ascii character (change the 94 to a higher number to include more characters)
        var randomCharacter = String.fromCharCode(33+Math.floor(Math.random()*94));
        ctx.fillText(randomCharacter , columns[i].x , columns[i].stackCounter*tileSize+tileSize);

        // if the stack is at its height limit, pick a new random height and reset the counter
        if (++columns[i].stackCounter >= columns[i].stackHeight)
        {
            columns[i].stackHeight = 10+Math.random()*maxStackHeight;
            columns[i].stackCounter = 0;
        }
    }
}

// MAIN LOOP
function tick() {
    draw();
    setTimeout(tick , 50);
}

var b_isFullscreen = false;

function fullscreen() {
    var elem = document.documentElement;
    if (elem.requestFullscreen) {
        elem.requestFullscreen();
    }
    else if (elem.webkitRequestFullscreen) {
        elem.webkitRequestFullscreen(); // Safari
    }
    else if (elem.msRequestFullscreen) {
        elem.msRequestFullscreen(); // IE11
    }
}

function exitFullscreen() {
    if (document.exitFullscreen) {
        document.exitFullscreen();
    }
    else if (document.webkitExitFullscreen) {
        document.webkitExitFullscreen(); // Safari
    }
    else if (document.msExitFullscreen) {
        document.msExitFullscreen(); // IE11
    }
}

function toggleFullscreen() {
    if (!b_isFullscreen) {
        fullscreen();
        b_isFullscreen = true;
    }
    else {
        exitFullscreen();
        b_isFullscreen = false;
    }
}

function updateTileSize() {
    tileSize = Math.min(Math.max(document.getElementById("tileSize").value , 10) , 100);
    initMatrix();
}

function updateFadeFactor() {
    fadeFactor = Math.min(Math.max(document.getElementById("fadeFactor").value , 0.0) , 1.0);
    initMatrix();
}


Maximum triangle path sum

Starting from the top of a pyramid of numbers like this, you can walk down going one step on the right or on the left, until you reach the bottom row:

                          55
                        94 48
                       95 30 96
                     77 71 26 67

One of such walks is 55 - 94 - 30 - 26.
You can compute the total of the numbers you have seen in such walk,
in this case it's 205.

Your problem is to find the maximum total among all possible paths from the top to the bottom row of the triangle. In the little example above it's 321.

;Task:
Find the maximum total in the triangle below:

                          55
                        94 48
                       95 30 96
                     77 71 26 67
                    97 13 76 38 45
                  07 36 79 16 37 68
                 48 07 09 18 70 26 06
               18 72 79 46 59 79 29 90
              20 76 87 11 32 07 07 49 18
            27 83 58 35 71 11 25 57 29 85
           14 64 36 96 27 11 58 56 92 18 55
         02 90 03 60 48 49 41 46 33 36 47 23
        92 50 48 02 36 59 42 79 72 20 82 77 42
      56 78 38 80 39 75 02 71 66 66 01 03 55 72
     44 25 67 84 71 67 11 61 40 57 58 89 40 56 36
   85 32 25 85 57 48 84 35 47 62 17 01 01 99 89 52
  06 71 28 75 94 48 37 10 23 51 06 48 53 18 74 98 15
27 02 92 23 08 71 76 84 15 52 92 63 81 10 44 10 69 93

Such numbers can be included in the solution code, or read from a "triangle.txt" file.

This task is derived from the Euler Problem #18.

Solution:
var arr = [
[55],
[94, 48],
[95, 30, 96],
[77, 71, 26, 67],
[97, 13, 76, 38, 45],
[07, 36, 79, 16, 37, 68],
[48, 07, 09, 18, 70, 26, 06],
[18, 72, 79, 46, 59, 79, 29, 90],
[20, 76, 87, 11, 32, 07, 07, 49, 18],
[27, 83, 58, 35, 71, 11, 25, 57, 29, 85],
[14, 64, 36, 96, 27, 11, 58, 56, 92, 18, 55],
[02, 90, 03, 60, 48, 49, 41, 46, 33, 36, 47, 23],
[92, 50, 48, 02, 36, 59, 42, 79, 72, 20, 82, 77, 42],
[56, 78, 38, 80, 39, 75, 02, 71, 66, 66, 01, 03, 55, 72],
[44, 25, 67, 84, 71, 67, 11, 61, 40, 57, 58, 89, 40, 56, 36],
[85, 32, 25, 85, 57, 48, 84, 35, 47, 62, 17, 01, 01, 99, 89, 52],
[06, 71, 28, 75, 94, 48, 37, 10, 23, 51, 06, 48, 53, 18, 74, 98, 15],
[27, 02, 92, 23, 08, 71, 76, 84, 15, 52, 92, 63, 81, 10, 44, 10, 69, 93]
];

while (arr.length !== 1) {
  var len = arr.length;
  var row = [];
  var current = arr[len-2];
  var currentLen = current.length - 1;
  var end = arr[len-1];

  for ( var i = 0; i <= currentLen; i++ ) {
    row.push(Math.max(current[i] + end[i] || 0, current[i] + end[i+1] || 0) )
  }

  arr.pop();
  arr.pop();

  arr.push(row);
}

console.log(arr);


Maximum triangle path sum

Solution:
(() => {
    "use strict";

    // ------------------ MAX PATH SUM -------------------

    // Working from the bottom of the triangle upwards,
    // summing each number with the larger of the two below
    // until the maximum emerges at the top.

    // maxPathSum ::[[Int]] -> Int
    const maxPathSum = xss =>
        // A list of lists folded down to a list of just one
        // remaining integer.
        foldr1(
            // The accumulator, zipped with the tail of the
            // accumulator, yields pairs of adjacent sums.
            (ys, xs) => zipWith3(

                // Plus greater of two below
                (a, b, c) => a + Math.max(b, c)
            )(xs)(ys)(ys.slice(1))
        )(xss)[0];

    // ---------------- GENERIC FUNCTIONS ----------------

    // foldr1 :: (a -> a -> a) -> [a] -> a
    const foldr1 = f =>
        xs => 0 < xs.length ? (
            xs.slice(0, -1).reduceRight(
                f, xs.slice(-1)[0]
            )
        ) : [];

    // zipWith3 :: (a -> b -> c -> d) ->
    // [a] -> [b] -> [c] -> [d]
    const zipWith3 = f =>
        xs => ys => zs => Array.from({
            length: Math.min(
                ...[xs, ys, zs].map(x => x.length)
            )
        }, (_, i) => f(xs[i], ys[i], zs[i]));

    // ---------------------- TEST -----------------------
    return maxPathSum([
        [55],
        [94, 48],
        [95, 30, 96],
        [77, 71, 26, 67],
        [97, 13, 76, 38, 45],
        [7, 36, 79, 16, 37, 68],
        [48, 7, 9, 18, 70, 26, 6],
        [18, 72, 79, 46, 59, 79, 29, 90],
        [20, 76, 87, 11, 32, 7, 7, 49, 18],
        [27, 83, 58, 35, 71, 11, 25, 57, 29, 85],
        [14, 64, 36, 96, 27, 11, 58, 56, 92, 18, 55],
        [2, 90, 3, 60, 48, 49, 41, 46, 33, 36, 47, 23],
        [92, 50, 48, 2, 36, 59, 42, 79, 72, 20, 82, 77, 42],
        [56, 78, 38, 80, 39, 75, 2, 71, 66, 66, 1, 3, 55, 72],
        [44, 25, 67, 84, 71, 67, 11, 61, 40, 57, 58, 89, 40, 56, 36],
        [85, 32, 25, 85, 57, 48, 84, 35, 47, 62, 17, 1, 1, 99, 89, 52],
        [6, 71, 28, 75, 94, 48, 37, 10, 23, 51, 6, 48, 53, 18, 74, 98, 15],
        [27, 2, 92, 23, 8, 71, 76, 84, 15, 52, 92, 63, 81, 10, 44, 10, 69, 93]
    ]);
})();


McNuggets problem

From Wikipedia:
 The McNuggets version of the coin problem was introduced by Henri Picciotto,
 who included it in his algebra textbook co-authored with Anita Wah. Picciotto
 thought of the application in the 1980s while dining with his son at
 McDonald's, working the problem out on a napkin. A McNugget number is
 the total number of McDonald's Chicken McNuggets in any number of boxes.
 In the United Kingdom, the original boxes (prior to the introduction of
 the Happy Meal-sized nugget boxes) were of 6, 9, and 20 nuggets.

;Task:
Calculate (from 0 up to a limit of 100) the largest non-McNuggets
number (a number ''n'' which cannot be expressed with ''6x + 9y + 20z = n''
where ''x'', ''y'' and ''z'' are natural numbers).

Solution:
(() => {
    'use strict';

    // main :: IO ()
    const main = () => {
        const
            size = n => enumFromTo(0)(
                quot(100, n)
            ),
            nuggets = new Set(
                size(6).flatMap(
                    x => size(9).flatMap(
                        y => size(20).flatMap(
                            z => {
                                const v = sum([6 * x, 9 * y, 20 * z]);
                                return 101 > v ? (
                                    [v]
                                ) : [];
                            }
                        ),
                    )
                )
            ),
            xs = dropWhile(
                x => nuggets.has(x),
                enumFromThenTo(100, 99, 1)
            );

        return 0 < xs.length ? (
            xs[0]
        ) : 'No unreachable quantities found in this range';
    };

    // GENERIC FUNCTIONS ----------------------------------

    // dropWhile :: (a -> Bool) -> [a] -> [a]
    const dropWhile = (p, xs) => {
        const lng = xs.length;
        return 0 < lng ? xs.slice(
            until(
                i => i === lng || !p(xs[i]),
                i => 1 + i,
                0
            )
        ) : [];
    };

    // enumFromThenTo :: Int -> Int -> Int -> [Int]
    const enumFromThenTo = (x1, x2, y) => {
        const d = x2 - x1;
        return Array.from({
            length: Math.floor(y - x2) / d + 2
        }, (_, i) => x1 + (d * i));
    };

    // ft :: Int -> Int -> [Int]
    const enumFromTo = m => n =>
        Array.from({
            length: 1 + n - m
        }, (_, i) => m + i);

    // quot :: Int -> Int -> Int
    const quot = (n, m) => Math.floor(n / m);

    // sum :: [Num] -> Num
    const sum = xs => xs.reduce((a, x) => a + x, 0);

    // until :: (a -> Bool) -> (a -> a) -> a -> a
    const until = (p, f, x) => {
        let v = x;
        while (!p(v)) v = f(v);
        return v;
    };

    // MAIN ---
    return console.log(
        main()
    );
})();


Mian-Chowla sequence

The Mian-Chowla sequence is an integer sequence defined recursively.

Mian-Chowla is an infinite instance of a Sidon sequence, and belongs to the class known as B2 sequences.

The sequence starts with:

::a1 = 1

then for n > 1, an is the smallest positive integer such that every pairwise sum

::ai + aj

is distinct, for all i and j less than or equal to n.

;The Task:

:* Find and display, here, on this page the first 30 terms of the Mian-Chowla sequence.
:* Find and display, here, on this page the 91st through 100th terms of the Mian-Chowla sequence.

Demonstrating working through the first few terms longhand:

::a1 = 1

::1 + 1 = 2

Speculatively try a2 = 2

::1 + 1 = 2
::1 + 2 = 3
::2 + 2 = 4

There are no repeated sums so '''2''' is the next number in the sequence.

Speculatively try a3 = 3

::1 + 1 = 2
::1 + 2 = 3
::1 + 3 = 4
::2 + 2 = 4
::2 + 3 = 5
::3 + 3 = 6

Sum of '''4''' is repeated so '''3''' is rejected.

Speculatively try a3 = 4

::1 + 1 = 2
::1 + 2 = 3
::1 + 4 = 5
::2 + 2 = 4
::2 + 4 = 6
::4 + 4 = 8

There are no repeated sums so '''4''' is the next number in the sequence.

And so on...

;See also:

:* OEIS:A005282 Mian-Chowla sequence

Solution:
(() => {
    'use strict';

    // main :: IO ()
    const main = () => {
        const genMianChowla = mianChowlas();
        console.log([
            'Mian-Chowla terms 1-30:',
            take(30)(
                genMianChowla
            ),

            '\nMian-Chowla terms 91-100:',
            (
                drop(60)(genMianChowla),
                take(10)(
                    genMianChowla
                )
            )
        ].join('\n') + '\n');
    };

    // mianChowlas :: Gen [Int]
    function* mianChowlas() {
        let
            mcs = [1],
            sumSet = new Set([2]),
            x = 1;
        while (true) {
            yield x;
            [sumSet, mcs, x] = nextMC(sumSet, mcs, x);
        }
    }

    // nextMC :: Set Int -> [Int] -> Int -> (Set Int, [Int], Int)
    const nextMC = (setSums, mcs, n) => {
        // Set of sums -> Series up to n -> Next term in series
        const valid = x => {
            for (const m of mcs) {
                if (setSums.has(x + m)) return false;
            }
            return true;
        };
        const x = until(valid)(x => 1 + x)(n);
        return [
            sumList(mcs)(x)
            .reduce(
                (a, n) => (a.add(n), a),
                setSums
            ),
            mcs.concat(x),
            x
        ];
    };

    // sumList :: [Int] -> Int -> [Int]
    const sumList = xs =>
        // Series so far -> additional term -> new sums
        n => [2 * n].concat(xs.map(x => n + x));

    // ---------------- GENERIC FUNCTIONS ----------------

    // drop :: Int -> [a] -> [a]
    // drop :: Int -> Generator [a] -> Generator [a]
    // drop :: Int -> String -> String
    const drop = n =>
        xs => Infinity > length(xs) ? (
            xs.slice(n)
        ) : (take(n)(xs), xs);

    // length :: [a] -> Int
    const length = xs =>
        // Returns Infinity over objects without finite
        // length. This enables zip and zipWith to choose
        // the shorter argument when one is non-finite,
        // like cycle, repeat etc
        'GeneratorFunction' !== xs.constructor
        .constructor.name ? (
            xs.length
        ) : Infinity;

    // take :: Int -> [a] -> [a]
    // take :: Int -> String -> String
    const take = n =>
        // The first n elements of a list,
        // string of characters, or stream.
        xs => 'GeneratorFunction' !== xs
        .constructor.constructor.name ? (
            xs.slice(0, n)
        ) : [].concat.apply([], Array.from({
            length: n
        }, () => {
            const x = xs.next();
            return x.done ? [] : [x.value];
        }));

    // until :: (a -> Bool) -> (a -> a) -> a -> a
    const until = p =>
        f => x => {
            let v = x;
            while (!p(v)) v = f(v);
            return v;
        };

    // MAIN ---
    return main();
})();


Middle three digits

Write a function/procedure/subroutine that is called with an integer value and returns the middle three digits of the integer if possible or a clear indication of an error if this is not possible.

Note: The order of the middle digits should be preserved.

Your function should be tested with the following values; the first line should return valid answers, those of the second line should return clear indications of an error:

123, 12345, 1234567, 987654321, 10001, -10001, -123, -100, 100, -12345
1, 2, -1, -10, 2002, -2002, 0

Show your output on this page.

Solution:
function middleThree(x){
  var n=''+Math.abs(x); var l=n.length-1;
  if(l<2||l%2) throw new Error(x+': Invalid length '+(l+1));
  return n.slice(l/2-1,l/2+2);
}

[123, 12345, 1234567, 987654321, 10001, -10001, -123, -100, 100, -12345,
1, 2, -1, -10, 2002, -2002, 0].forEach(function(n){
  try{console.log(n,middleThree(n))}catch(e){console.error(e.message)}
});


Middle three digits

Solution:
(() => {
    'use strict';

    // mid3digits :: Int -> Either String String
    const mid3digits = n => {
        const
            m = abs(n),
            s = m.toString();
        return 100 > m ? (
            Left('Less than 3 digits')
        ) : even(length(s)) ? (
            Left('Even digit count')
        ) : Right(take(3, drop(quot(length(s) - 3, 2), s)));
    };

    // TEST -----------------------------------------------
    const main = () => {
        const
            xs = [
                123, 12345, 1234567, 987654321, 10001, -10001, -123,
                -100, 100, -12345, 1, 2, -1, -10, 2002, -2002, 0
            ],
            w = maximum(map(x => x.toString().length, xs));
        return (
            unlines(map(
                n => justifyRight(w, ' ', n.toString()) + ' -> ' +
                either(
                    s => '(' + s + ')',
                    id,
                    mid3digits(n)
                ),
                xs
            ))
        );
    };

    // GENERIC FUNCTIONS ----------------------------------

    // Left :: a -> Either a b
    const Left = x => ({
        type: 'Either',
        Left: x
    });

    // Right :: b -> Either a b
    const Right = x => ({
        type: 'Either',
        Right: x
    });

    // abs :: Num -> Num
    const abs = Math.abs;

    // drop :: Int -> [a] -> [a]
    // drop :: Int -> Generator [a] -> Generator [a]
    // drop :: Int -> String -> String
    const drop = (n, xs) =>
        Infinity > length(xs) ? (
            xs.slice(n)
        ) : (take(n, xs), xs);

    // either :: (a -> c) -> (b -> c) -> Either a b -> c
    const either = (fl, fr, e) =>
        'Either' === e.type ? (
            undefined !== e.Left ? (
                fl(e.Left)
            ) : fr(e.Right)
        ) : undefined;

    // even :: Int -> Bool
    const even = n => 0 === n % 2;

    // foldl1 :: (a -> a -> a) -> [a] -> a
    const foldl1 = (f, xs) =>
        1 < xs.length ? xs.slice(1)
        .reduce(f, xs[0]) : xs[0];

    // id :: a -> a
    const id = x => x;

    // justifyRight :: Int -> Char -> String -> String
    const justifyRight = (n, cFiller, s) =>
        n > s.length ? (
            s.padStart(n, cFiller)
        ) : s;

    // Returns Infinity over objects without finite length.
    // This enables zip and zipWith to choose the shorter
    // argument when one is non-finite, like cycle, repeat etc

    // length :: [a] -> Int
    const length = xs =>
        (Array.isArray(xs) || 'string' === typeof xs) ? (
            xs.length
        ) : Infinity;

    // maximum :: Ord a => [a] -> a
    const maximum = xs =>
        0 < xs.length ? (
            foldl1((a, x) => x > a ? x : a, xs)
        ) : undefined;

    // map :: (a -> b) -> [a] -> [b]
    const map = (f, xs) => xs.map(f);

    // quot :: Int -> Int -> Int
    const quot = (n, m) => Math.floor(n / m);

    // take :: Int -> [a] -> [a]
    // take :: Int -> String -> String
    const take = (n, xs) =>
        'GeneratorFunction' !== xs.constructor.constructor.name ? (
            xs.slice(0, n)
        ) : [].concat.apply([], Array.from({
            length: n
        }, () => {
            const x = xs.next();
            return x.done ? [] : [x.value];
        }));

    // unlines :: [String] -> String
    const unlines = xs => xs.join('\n');

    // MAIN ---
    return main();
})();


Mind boggling card trick

Matt Parker of the "Stand Up Maths channel" has a   YouTube video   of a card trick that creates a semblance of order from chaos.

The task is to simulate the trick in a way that mimics the steps shown in the video.

; 1. Cards.
# Create a common deck of cards of 52 cards    (which are half red, half black).
# Give the pack a good shuffle.
; 2. Deal from the shuffled deck, you'll be creating three piles.
#   Assemble the cards face down.
##   Turn up the   ''top card''   and hold it in your hand.
###    if the card is         black,        then add the   ''next''   card (unseen) to the       "black"      pile.
###    If the card is     red,    then add the   ''next''   card (unseen) to the   "red"  pile.
##   Add the   ''top card''   that you're holding to the '''discard''' pile.   (You might optionally show these discarded cards to get an idea of the randomness).
# Repeat the above for the rest of the shuffled deck.
; 3. Choose a random number   (call it '''X''')   that will be used to swap cards from the "red" and "black" piles.
# Randomly choose   '''X'''   cards from the   "red"  pile (unseen), let's call this the   "red"  bunch.
# Randomly choose   '''X'''   cards from the       "black"      pile (unseen), let's call this the      "black"       bunch.
# Put the     "red"    bunch into the         "black"      pile.
# Put the        "black"        bunch into the      "red"  pile.
# (The above two steps complete the swap of   '''X'''   cards of the "red" and "black" piles.  (Without knowing what those cards are --- they could be red or black, nobody knows).
; 4. Order from randomness?
# Verify (or not) the mathematician's assertion that:
      '''The number of black cards in the "black" pile equals the number of red cards in the "red" pile.'''

(Optionally, run this simulation a number of times, gathering more evidence of the truthfulness of the assertion.)

Show output on this page.

Solution:
(() => {
    'use strict';

    const main = () => {
        const
        // DEALT
        [rs_, bs_, discards] = threeStacks(
                map(n =>
                    even(n) ? (
                        'R'
                    ) : 'B', knuthShuffle(
                        enumFromTo(1, 52)
                    )
                )
            ),

            // SWAPPED
            nSwap = randomRInt(1, min(rs_.length, bs_.length)),
            [rs, bs] = exchange(nSwap, rs_, bs_),

            // CHECKED
            rrs = filter(c => 'R' === c, rs).join(''),
            bbs = filter(c => 'B' === c, bs).join('');
        return unlines([
            'Discarded: ' + discards.join(''),
            'Swapped: ' + nSwap,
            'Red pile: ' + rs.join(''),
            'Black pile: ' + bs.join(''),
            rrs + ' = Red cards in the red pile',
            bbs + ' = Black cards in the black pile',
            (rrs.length === bbs.length).toString()
        ]);
    };

    // THREE STACKS ---------------------------------------

    // threeStacks :: [Chars] -> ([Chars], [Chars], [Chars])
    const threeStacks = cards => {
        const go = ([rs, bs, ds]) => xs => {
            const lng = xs.length;
            return 0 < lng ? (
                1 < lng ? (() => {
                    const [x, y] = take(2, xs),
                        ds_ = cons(x, ds);
                    return (
                        'R' === x ? (
                            go([cons(y, rs), bs, ds_])
                        ) : go([rs, cons(y, bs), ds_])
                    )(drop(2, xs));
                })() : [rs, bs, ds_]
            ) : [rs, bs, ds];
        };
        return go([
            [],
            [],
            []
        ])(cards);
    };

    // exchange :: Int -> [a] -> [a] -> ([a], [a])
    const exchange = (n, xs, ys) => {
        const [xs_, ys_] = map(splitAt(n), [xs, ys]);
        return [
            fst(ys_).concat(snd(xs_)),
            fst(xs_).concat(snd(ys_))
        ];
    };

    // SHUFFLE --------------------------------------------

    // knuthShuffle :: [a] -> [a]
    const knuthShuffle = xs =>
        enumFromTo(0, xs.length - 1)
        .reduceRight((a, i) => {
            const iRand = randomRInt(0, i);
            return i !== iRand ? (
                swapped(i, iRand, a)
            ) : a;
        }, xs);

    // swapped :: Int -> Int -> [a] -> [a]
    const swapped = (iFrom, iTo, xs) =>
        xs.map(
            (x, i) => iFrom !== i ? (
                iTo !== i ? (
                    x
                ) : xs[iFrom]
            ) : xs[iTo]
        );

    // GENERIC FUNCTIONS ----------------------------------

    // cons :: a -> [a] -> [a]
    const cons = (x, xs) =>
        Array.isArray(xs) ? (
            [x].concat(xs)
        ) : (x + xs);

    // drop :: Int -> [a] -> [a]
    // drop :: Int -> String -> String
    const drop = (n, xs) => xs.slice(n);

    // enumFromTo :: Int -> Int -> [Int]
    const enumFromTo = (m, n) =>
        m <= n ? iterateUntil(
            x => n <= x,
            x => 1 + x,
            m
        ) : [];

    // even :: Int -> Bool
    const even = n => 0 === n % 2;

    // filter :: (a -> Bool) -> [a] -> [a]
    const filter = (f, xs) => xs.filter(f);

    // fst :: (a, b) -> a
    const fst = tpl => tpl[0];

    // iterateUntil :: (a -> Bool) -> (a -> a) -> a -> [a]
    const iterateUntil = (p, f, x) => {
        const vs = [x];
        let h = x;
        while (!p(h))(h = f(h), vs.push(h));
        return vs;
    };

    // map :: (a -> b) -> [a] -> [b]
    const map = (f, xs) => xs.map(f);

    // min :: Ord a => a -> a -> a
    const min = (a, b) => b < a ? b : a;

    // randomRInt :: Int -> Int -> Int
    const randomRInt = (low, high) =>
        low + Math.floor(
            (Math.random() * ((high - low) + 1))
        );

    // snd :: (a, b) -> b
    const snd = tpl => tpl[1];

    // splitAt :: Int -> [a] -> ([a],[a])
    const splitAt = n => xs => Tuple(xs.slice(0, n), xs.slice(n));

    // take :: Int -> [a] -> [a]
    const take = (n, xs) => xs.slice(0, n);

    // Tuple (,) :: a -> b -> (a, b)
    const Tuple = (a, b) => ({
        type: 'Tuple',
        '0': a,
        '1': b,
        length: 2
    });

    // unlines :: [String] -> String
    const unlines = xs => xs.join('\n');

    // MAIN ---
    return main();
})();


Modular inverse

From Wikipedia:

In modulo    ''m''    is an integer    ''x''    such that

::a\,x \equiv 1 \pmod{m}.

Or in other words, such that:

::\exists k \in\Z,\qquad a\, x = 1 + k\,m

It can be shown that such an inverse exists   if and only if    ''a''    and    ''m''    are coprime,   but we will ignore this for this task.

;Task:
Either by implementing the algorithm, by using a dedicated library or by using a built-in function in
your language,   compute the modular inverse of   42 modulo 2017.

Solution:
var modInverse = function(a, b) {
    a %= b;
    for (var x = 1; x < b; x++) {
        if ((a*x)%b == 1) {
            return x;
        }
    }
}


Monads/List monad

A Monad is a combination of a data-type with two helper functions written for that type.

The data-type can be of any kind which can contain values of some other type - common examples are lists, records, sum-types, even functions or IO streams. The two special functions, mathematically known as '''eta''' and '''mu''', but usually given more expressive names like 'pure', 'return', or 'yield' and 'bind', abstract away some boilerplate needed for pipe-lining or enchaining sequences of computations on values held in the containing data-type.

The bind operator in the List monad enchains computations which return their values wrapped in lists. One application of this is the representation of indeterminacy, with returned lists representing a set of possible values. An empty list can be returned to express incomputability, or computational failure.

A sequence of two list monad computations (enchained with the use of bind) can be understood as the computation of a cartesian product.

The natural implementation of bind for the List monad is a composition of '''concat''' and '''map''', which, used with a function which returns its value as a (possibly empty) list, provides for filtering in addition to transformation or mapping.

Demonstrate in your programming language the following:

#Construct a List Monad by writing the 'bind' function and the 'pure' (sometimes known as 'return') function for that Monad (or just use what the language already has implemented)
#Make two functions, each which take a number and return a monadic number, e.g. Int -> List Int and Int -> List String
#Compose the two functions with bind

Solution:
(function (n) {

    // ENCODING A SET COMPREHENSION IN TERMS OF A LIST MONAD

    // Pythagorean triples drawn from integers in the range [1..25]

    // Each range of integers here represents the set of possible values for the variable.
    // Where the test returns true for a particular [x, y, z] triple, we return that triple
    // to the expected data type, wrapping it using the unit or return function;

    // Where the test returns false, we return the empty list, which vanishes from the
    // results set under concatenation, giving us a convenient encoding of filtering.

    // {(x, y, z) | x <- [1..n], y <- [x+1..n], z <- [y+1..n], (x^2 + y^2 = z^2)}

    return bind(rng(1,     n), function (x) {
    return bind(rng(1 + x, n), function (y) {
    return bind(rng(1 + y, n), function (z) {

        return (x * x + y * y === z * z) ? unit([x, y, z]) : [];

    })})});

    // Monadic return/unit/inject for lists just wraps a value in a list
    // a -> [a]
    function unit(a) {
        return [a];
    }

    // Bind for lists is simply ConcatMap
    // which applies a function f directly to each value in the list,
    // and returns the set of results as a concat-flattened list
    // [a] -> (a -> [b]) -> [b]
    function bind(xs, f) {
        return [].concat.apply([], xs.map(f));
    }

    // we will need some ranges of integers, each expressing a range of possible values
    // [m..n]
    function rng(m, n) {
        return Array.apply(null, Array(n - m + 1))
            .map(function (x, i) {
                return m + i;
            });
    }

})(25);


Monads/Maybe monad

Demonstrate in your programming language the following:

#Construct a Maybe Monad by writing the 'bind' function and the 'unit' (sometimes known as 'return') function for that Monad (or just use what the language already has implemented)
#Make two functions, each which take a number and return a monadic number, e.g. Int -> Maybe Int and Int -> Maybe String
#Compose the two functions with bind

A Monad is a single type which encapsulates several other types, eliminating boilerplate code. In practice it acts like a dynamically typed computational sequence, though in many cases the type issues can be resolved at compile time.

A Maybe Monad is a monad which specifically encapsulates the type of an undefined value.

Solution:
(function () {
    'use strict';

    // START WITH SOME SIMPLE (UNSAFE) PARTIAL FUNCTIONS:

    // Returns Infinity if n === 0
    function reciprocal(n) {
        return 1 / n;
    }

    // Returns NaN if n < 0
    function root(n) {
        return Math.sqrt(n);
    }

    // Returns -Infinity if n === 0
    // Returns NaN if n < 0
    function log(n) {
        return Math.log(n);
    }

    // NOW DERIVE SAFE VERSIONS OF THESE SIMPLE FUNCTIONS:
    // These versions use a validity test, and return a wrapped value
    // with a boolean .isValid property as well as a .value property

    function safeVersion(f, fnSafetyCheck) {
        return function (v) {
            return maybe(fnSafetyCheck(v) ? f(v) : undefined);
        }
    }

    var safe_reciprocal = safeVersion(reciprocal, function (n) {
        return n !== 0;
    });

    var safe_root = safeVersion(root, function (n) {
        return n >= 0;
    });

    var safe_log = safeVersion(log, function (n) {
        return n > 0;
    });

    // THE DERIVATION OF THE SAFE VERSIONS USED THE 'UNIT' OR 'RETURN'
    // FUNCTION OF THE MAYBE MONAD

    // Named maybe() here, the unit function of the Maybe monad wraps a raw value
    // in a datatype with two elements: .isValid (Bool) and .value (Number)

    // a -> Ma
    function maybe(n) {
        return {
            isValid: (typeof n !== 'undefined'),
            value: n
        };
    }

    // THE PROBLEM FOR FUNCTION NESTING (COMPOSITION) OF THE SAFE FUNCTIONS
    // IS THAT THEIR INPUT AND OUTPUT TYPES ARE DIFFERENT

    // Our safe versions of the functions take simple numeric arguments, but return
    // wrapped results. If we feed a wrapped result as an input to another safe function,
    // it will choke on the unexpected type. The solution is to write a higher order
    // function (sometimes called 'bind' or 'chain') which handles composition, taking a
    // a safe function and a wrapped value as arguments,

    // The 'bind' function of the Maybe monad:
    // 1. Applies a 'safe' function directly to the raw unwrapped value, and
    // 2. returns the wrapped result.

    // Ma -> (a -> Mb) -> Mb
    function bind(maybeN, mf) {
        return (maybeN.isValid ? mf(maybeN.value) : maybeN);
    }

    // Using the bind function, we can nest applications of safe_ functions,
    // without their choking on unexpectedly wrapped values returned from
    // other functions of the same kind.
    var rootOneOverFour = bind(
        bind(maybe(4), safe_reciprocal), safe_root
    ).value;

    // -> 0.5

    // We can compose a chain of safe functions (of any length) with a simple foldr/reduceRight
    // which starts by 'lifting' the numeric argument into a Maybe wrapping,
    // and then nests function applications (working from right to left)
    function safeCompose(lstFunctions, value) {
        return lstFunctions
            .reduceRight(function (a, f) {
                return bind(a, f);
            }, maybe(value));
    }

    // TEST INPUT VALUES WITH A SAFELY COMPOSED VERSION OF LOG(SQRT(1/X))

    var safe_log_root_reciprocal = function (n) {
        return safeCompose([safe_log, safe_root, safe_reciprocal], n).value;
    }

    return [-2, -1, -0.5, 0, 1 / Math.E, 1, 2, Math.E, 3, 4, 5].map(
        safe_log_root_reciprocal
    );

})();