"use strict"; 4 chapter("Hi-order functions"); section("Minimum by absolute value"); let minimumByAbs = function(...args) { let result = Infinity; for (const arg of args) { if (Math.abs(result) > Math.abs(arg)) { result = arg; } } return result; }; println("minimumByAbs =", minimumByAbs); example("minimumByAbs(1, -2, 3)"); section("Unify minimum and minimumByAbs"); subsection("High-order functions"); function minimumBy(comparator, init = Infinity) { return (...args) => { let result = init; for (const arg of args) { if (comparator(result, arg) > 0) { result = arg; } } return result; } } println(minimumBy); function comparing(f) { return (a, b) => f(a) - f(b); } println(comparing); const identity = a => a; println("const identity =", identity); function maximumBy(comparator, init = -Infinity) { return minimumBy((a, b) => -comparator(a, b), init); } println(maximumBy); subsection("Definitions"); let minimumByV = minimumBy(comparing(identity)); minimumByAbs = minimumBy(comparing(Math.abs)); let maximumByLength = maximumBy(comparing(s => s.length), ""); example("minimumByV"); example("minimumByAbs"); example("maximumByLength"); example("minimumByV(1, -2, 3)"); example("minimumByAbs(1, -2, 3)"); example("maximumByLength('aa', 'bbb', 'c')"); section("Unify minimumBy and sum"); subsection("High-order functions"); function foldLeft(f, zero) { return (...args) => { let result = zero; for (const arg of args) { result = f(result, arg); } return result; } } println(foldLeft); function minBy(f) { return (a, b) => f(a) < f(b) ? a : b; } println(minBy); subsection("Definitions"); const sum2 = foldLeft((a, b) => a + b, 0); const product = foldLeft((a, b) => a * b, 1); minimumByAbs = foldLeft(minBy(comparing(Math.abs)), Infinity); example("sum2(1, -2, 3)"); example("product(1, -2, 3)"); example("minimumByAbs(1, -2, 3)"); section("sumSquares and sumAbs"); let square = x => x * x; let sumSquares = foldLeft((a, b) => a + square(b), 0); let sumAbs = foldLeft((a, b) => a + Math.abs(b), 0); example("sumSquares(1, -2, 3)"); example("sumAbs(1, -2, 3)"); subsection("High-order functions"); function map(f) { return (...args) => { const result = []; for (const arg of args) { result.push(f(arg)); } return result; } } println(map); function compose(f, g) { return (...args) => f(g(...args)); } println(compose); function unspread(f) { return args => f(...args); } println(unspread); subsection("Definitions"); sumSquares = compose(unspread(sum2), map(square)); sumAbs = compose(unspread(sum2), map(Math.abs)); example("sumSquares(1, -2, 3)"); example("sumAbs(1, -2, 3)"); section("diff"); let diff = dx => f => x => (f(x + dx) - f(x - dx)) / 2 / dx; let dsin = diff(1e-7)(Math.sin); for (let i = 0; i < 10; i++) { println(i + " " + Math.cos(i) + " " + dsin(i) + " " + Math.abs(Math.cos(i) - dsin(i))); } section("Currying"); subsection("curry"); const curry = f => a => b => f(a, b); const addC = curry((a, b) => a + b); const add10 = addC(10); example("addC(10)(20)"); example("add10(20)"); subsection("uncurry"); const uncurry = f => (a, b) => f(a)(b); const addU = uncurry(a => b => a + b); example("addU(10, 20)"); subsection("mCurry"); println("bind"); let bind = (f, ...as) => (...args) => f(...[...as, ...args]); let add100 = bind((a, b) => a + b, 100); example(" add100(200)"); println("mCurry"); let mCurry = curry(bind); let sub = mCurry((a, b, c) => a - b - c); let sub10 = sub(10); example(" sub(10)(20, 30)"); example(" sub10(20, 30)");