Published
Edited
Jan 10, 2020
Insert cell
Insert cell
// Use the higher order multiplier and adder functions to create partial functions that respectively
// double and add 5 to their subsequent operands
double = lib.multiplier(2)
Insert cell
add5 = lib.adder(5)
Insert cell
// Double a number, then add 5 to it
add5(double(3))
Insert cell
// Create a higher order function that can combine, or "compose", the functionality of two other functions
compose = fn1 => fn2 => val => fn2(fn1(val))
Insert cell
// Now we can take the double and add5 function and "compose" them into a single function
doubleAndAdd5 = compose(double)(add5)
Insert cell
Insert cell
Insert cell
fp_cos = {
// Find the fixed point of the Cosine function (in radians)
var x = 3;
while (x !== Math.cos(x)) {
x = Math.cos(x)
}
return x;
}
Insert cell
Insert cell
{
// Apply Tennent's Correspondence Principle (TCP) to the multiplier &
// adder functions.
// var multiplier = p => q => q*p;
// var adder = p => q => q+p;
// becomes:
var multiplier = p => q => (() => q*p)();
var adder = p => q => (() => q+p)();

// Now apply TCP to the double and add5 functions
// var double = multiplier(2);
// var add5 = adder(5);
// becomes:
var double = (() => multiplier(2))();
var add5 = (() => adder(5))();

// Finally, apply TCP to the compose function
// var compose = fn1 => fn2 => val => fn2(fn1(val));
// becomes:
var compose = fn1 => fn2 => (() => val => fn2(fn1(val)))();

// Compose function doubleAndAdd5 as before
var doubleAndAdd5 = compose(double)(add5);

// TCP refactoring has no effect on the final result
return doubleAndAdd5(3);
}
Insert cell
Insert cell
{
// Each of the self-executing functions inside multiplier and adder
// now take a parameter "z". Since "z" is not used anywhere inside
// either expression, we are free to assign this parameter any
// value we like: hence the 123 and "abc".
// In this case, these values have absolutely no effect on the
// evaluation of the expression.
var multiplier = p => q => (z => q*p)(123);
var adder = p => q => (z => q+p)("abc");

// Create the double and add5 partial functions as before
var double = (() => multiplier(2))();
var add5 = (() => adder(5))();

// Create a "compose" higher order function
var compose = fn1 => fn2 => (() => val => fn2(fn1(val)))();

// Compose function doubleAndAdd5 as before
var doubleAndAdd5 = compose(double)(add5);

// Supplying values to unused parameters has no effect on the final
// result
return doubleAndAdd5(3); // -> 11, just the same as before
}
Insert cell
Insert cell
{
// The multiplier and adder functions without TCP refactoring
// var multiplier = p => q => q*p;
// var adder = p => q => q+p;

// Refactor each function by wrapping it in a self-executing function that takes an unused parameter z
var multiplier = p => z => (q => q*p)(z);
var adder = p => z => (q => q+p)(z);

// Create the double and add5 partial functions as before
var double = multiplier(2);
var add5 = adder(5);

// Create a "compose" higher order function
var compose = fn1 => fn2 => val => fn2(fn1(val));

// Compose function doubleAndAdd5 as before
var doubleAndAdd5 = compose(double)(add5);

// Function wrapping has no effect on the final result
return doubleAndAdd5(3);
}
Insert cell
Insert cell
{
// Treat the "multiplier" and "adder" functions as if they are macros
// var multiplier = p => q => q*p;
// var adder = p => q => q+p;
// So instead of writing
// var double = multiplier(2);
// var add5 = adder(5);
// we write
var double = (p => q => q*p)(2);
var add5 = (p => q => q+p)(5);
return add5(double(3));
}
Insert cell
Insert cell
{
// Functions "double" and "add5" are no longer needed explicitly
// because we replace all occurrences of their names with their
// definition
// var double = (p => q => q*p)(2);
// var add5 = (p => q => q+p)(5);

// Create a "compose" higher order function
var compose = fn1 => fn2 => val => fn2(fn1(val));

// Replace occurrences of double and add5
var doubleAndAdd5 = compose((p => q => q*p)(2))((p => q => q+p)(5));

return doubleAndAdd5(3);
}
Insert cell
Insert cell
{
// Now "compose" is no longer needed as a named function
// var compose = fn1 => fn2 => val => fn2(fn1(val));

// Replace occurrences of compose (with some CRLFs for clarity)
var doubleAndAdd5 = (fn1 => fn2 => val => fn2(fn1(val)))
((p => q => q*p)(2))
((p => q => q+p)(5));

return doubleAndAdd5(3);
}
Insert cell
Insert cell
// Replace doubleAndAdd5 with its own definition and take out
// the helpful spaces and carriage returns

// This yields possibly the most cryptic piece of JavaScript you've
// ever seen; but that's not the point. The point is that:
// a) it works and,
// b) we can be very confident of its correctness because we have
// derived this expression from first principles!

(fn1=>fn2=>val=>fn2(fn1(val)))((p=>q=>q*p)(2))((p=>q=>q+p)(5))(3)
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more