CC-BY-NC-4.0 / Mar. 2020 / Loïc TRUCHOT
How do you call people that can:
function openEyes () {
console.log("The truth is coming out");
}
openEyes();
const openMind = () => "It can make you blind.";
const mind = openMind;
const msg = mind();
What dot you see when you think about an exclusive OR ?
imperative
declarative
electricity -> transistors -> binary -> assembly -> AST -> language -> symbols
(true && true) && (true && false); // transistor
0b11 + 0b10; // binary
2 + 3; // imperative addition
add(2, 3); // declarative addition
Ritual
The only secret to controlling complexity is not to focus on the details.
function clone (o) {
return JSON.parse(JSON.stringify(o));
}
// OR shortly
const clone = (o) => JSON.parse(JSON.stringify(o));
Secret
a wise choice
// imperative, via statements
let statementMessage = '';
if (age < 18) {
statementMessage = 'You shall not pass!';
} else {
statementMessage = 'Welcome to the ceremony...';
}
console.log(statementMessage);
// declarative via expressions
function ifElse(cond, ok, notOk) {
if (cond) { // predicate
return ok; // consequent
}
return notOk; // alternative
}
console.log(ifElse(age < 18, 'Go back !', 'Welcome'));
// AKA ternary, which is an expression too
console.log(age < 18 ? 'Go back !' : 'Welcome');
What about a pure function ?
Ritual
and transparent
const prop = (key, obj) => obj[key];
Secret
including mutations
const not = (val) => !val;
const nlp = pipe(
purify,
parse,
splitWords,
inferMeaning,
combineResults
);
nlp("Some dangerous stuff.");
let content = 'Turn cat into bat';
const nouns = ['cat', 'owl', 'bat', 'wand'];
function extractNouns() {
const extractedNouns = [];
const arr = content.split(' ');
for (let i = 0; i < arr.length; i++) {
for (let j = 0; j < nouns.length; j++) {
if (nouns[j] === arr[i]) {
extractedNouns.push(arr[i]);
}
}
}
content = extractedNouns;
}
extractNouns();
console.log(content);
const includes = (arr, w) => {
for (let i = 0; i < arr.length; i++) {
if (arr[i] === w) return true;
}
};
const filterWords = (arr, words) => {
const filtered = [];
for (let i = 0; i < words.length; i++) {
if (includes(arr, words[i])) {
filtered.push(words[i]);
}
}
return filtered;
};
const extractNouns = (nouns, content) => {
const words = content.split(' ');
return filterWords(nouns, words);
};
const content = 'Turn cat into bat';
const nouns = ['cat', 'owl', 'bat', 'wand'];
const result = extractNouns(nouns, content);
console.log(result);
Readability / Reasonability ?
Name collision?
Value tracking ? Reason about ?
Reusability ? Testing ?
But still get functions dependencies...
+(3, 5) // 8
concat("Hello", " ", "World!) // "Hello World!"
combineWeddingVideos("drink.mp4", "dance.mp4")
Ritual
const avadaKedavra = (human) => `${human} is dead.`;
const episkey = (human) => `${human} is healed.`;
const spells = [avadaKedavra, episkey];
const rand = (arr) => arr[Math.floor(Math.random() * arr.length)];
const me = 'Loïc';
const result = rand(spells)(me);
console.log(result); // dead or alive?
Secret
Ritual
functions as input or as output
const laugh = () => console.log('Muhahaha...');
document.getElementById('poison').addEventListener('click', laugh);
Promise.resolve('spider web').then((obj) => console.log(`eat ${obj}`));
const forEach = (func, arr) => {
for (let i = 0; i < arr.length; i++) {
func(arr[i]);
}
};
forEach(console.log, ['Cthulhu', 'Shoggoth']);
['Cthulhu', 'Shoggoth'].forEach(laugh);
const map = (func, arr) => {
const newArr = [];
for (const el of arr) {
const newEl = func(el); newArr.push(newEl);
}
return newArr;
};
const eat = (thing) => `I just ate this ${thing}. Tasty.`;
map(eat, ['spider', 'crow']).forEach(console.log),
forEach(
(b) => console.log(`${b} blood liters`),
map((item) => item.blood, [
{ name: 'cat', blood: 2 },
{ name: 'snake', blood: 0.4 },
]),
);
{ 1, 2, 3 } -> double -> { 2, 4, 6 }
as examples of expressiveness and DRY
const setOnFire = (a) => {
const b = 'wood';
const burn = () => {
console.log(`${a}is burning in the ${b}`);
};
burn();
};
const setOnFire = (a) => {
const b = 'wood';
const burn = () => {
console.log(`${a}is burning in the ${b}`);
};
return burn;
};
const makeItBurn = setOnFire('bat');
makeItBurn();
const eat = (thing) => `I just ate a ${thing}. Tasty.`;
const forEach = (func) => (arr) => {
for (let i = 0; i < arr.length; i++) { func(arr[i]); }
};
const map = (func) => (arr) => { /* ... */ };
const logEach = forEach(console.log);
const eatAll = map(eat);
logEach(['spider', 'bat', 'cat', 'owl']);
logEach(eatAll(['Cthulhu', 'Shoggoth']));
Secret
Ritual
Refuse God Objects
[].map(); // OK
Animal.map(); // NOT OK
const beFrightening = a => a + " is frightening";
beFrightening("cat");
beFrightening("sky");
beFrightening("mystery");
combining functions
const prop = (key) => (obj) => obj[key];
forEach(
(b) => console.log(`${b} liters`),
)(
map(prop('blood'))([
{ name: 'cat', blood: 2 }, { name: 'snake', blood: 0.4 },
]),
);
const filter = (f) => (arr) => arr.filter(f);
const pipe3 = (f1, f2, f3) => (arg) => {
f3(f2(f1(arg)));
};
const add = (a) => (b) => a + b;
pipe3(add(111), add(111), console.log)(444);
pipe3(
filter((item) => item.blood > 0.1),
map(prop('blood')),
forEach((b) => console.log(`${b} liters`)),
)([{ name: 'cat', blood: 2 }, { name: 'snake', blood: 0.4 }]);
Secret
Ritual
const bools = [true, false, true];
const ints = [1, 2, 3];
console.log(bools[0] && bools[1] && bools[2]);
console.log(ints[0] + ints[1] + ints[2]);
const reduce = (operation, neutral) => (arr) => {
let acc = neutral;
for (const el of arr) {
acc = operation(acc, el);
}
return acc;
};
const sum = reduce((a, b) => a + b, 0);
const all = reduce((a, b) => a && b, true);
console.log(sum(ints));
console.log(all(bools));
const max = reduce((a, b) => (a > b ? a : b), -Infinity);
console.log(max(ints));
const pipe = reduce((f, g) => (arg) => g(f(arg)), (a) => a);
const add = (a) => (b) => a + b;
pipe([add(111), add(111), console.log])(444);
Secret
Ritual
recursion over loops
const list = ['spider', 'cat', 'bat'];
const recurse = (func, arr) => {
if (arr.length) {
const [head, ...tail] = arr;
func(head);
recurse(func, tail);
}
};
recurse(console.log, list);
I felt a great disturbance in the Force
Java
Ruby
C++
C#
Objective C
Angular
Scala
Elixir
Clojure
Rust
F#
Swift
React
Reason
Elm, PureScript...
Java 8 -> lambda
PHP 7 -> HOF...
LISP
Erlang
OCaml
Haskell
JS & Python ?
Function are alreadyfirst class citizen
Secret
...and prepare to be hated and burnt