Slide 1

Slide 1 text

Functional Programming Basics in JavaScript 2:40 PM / Ballroom A

Slide 2

Slide 2 text

Functional Programming Basics in JavaScript Jeremy Fairbank @elpapapollo

Slide 3

Slide 3 text

Understand, apply, and create basic functional programming tenets and constructs in JavaScript.

Slide 4

Slide 4 text

Hi, I’m Jeremy jfairbank @elpapapollo pushagency.io blog.jeremyfairbank.com simplybuilt.com

Slide 5

Slide 5 text

What is a function?

Slide 6

Slide 6 text

What is a function?

Slide 7

Slide 7 text

What is a function? Relation that pairs each element in the domain with exactly one element in the range. Domain Range

Slide 8

Slide 8 text

What is a function?

Slide 9

Slide 9 text

What is a function?

Slide 10

Slide 10 text

What is a function?

Slide 11

Slide 11 text

What is a function? Domain

Slide 12

Slide 12 text

What is a function? Domain Range

Slide 13

Slide 13 text

Unique mapping from input to output! Domain Range

Slide 14

Slide 14 text

Ugh, math?

Slide 15

Slide 15 text

Alonzo Church

Slide 16

Slide 16 text

Alonzo Church • Church-Turing Thesis • Lambda Calculus • Represent computation in terms of “function abstraction and application using variable binding and substitution.”

Slide 17

Slide 17 text

λ-Calculus Represent computation in terms of “function abstraction and application using variable binding and substitution.”

Slide 18

Slide 18 text

Represent computation in terms of “function abstraction and application using variable binding and substitution.” λ-Calculus

Slide 19

Slide 19 text

Represent computation in terms of “function abstraction and application using variable binding and substitution.” λ-Calculus Bind “x” to function => parameters

Slide 20

Slide 20 text

Represent computation in terms of “function abstraction and application using variable binding and substitution.” λ-Calculus Substitution => apply arguments

Slide 21

Slide 21 text

λ-Calculus Functions are anonymous.

Slide 22

Slide 22 text

Functions are anonymous. λ-Calculus

Slide 23

Slide 23 text

Functions are anonymous. λ-Calculus X

Slide 24

Slide 24 text

Functions are anonymous. λ-Calculus Functions are expressions and units of computation.

Slide 25

Slide 25 text

λ-Calculus Functions are single input.

Slide 26

Slide 26 text

Functions are single input. λ-Calculus

Slide 27

Slide 27 text

Functions are single input. λ-Calculus

Slide 28

Slide 28 text

Functions are single input. λ-Calculus Break down into smaller pieces — currying!

Slide 29

Slide 29 text

That’s nice. What about functional programming?

Slide 30

Slide 30 text

λ-Calculus shows the power of functional computation. Functional programming brings it to life in computer science!

Slide 31

Slide 31 text

What is Functional Programming?

Slide 32

Slide 32 text

– Wikipedia “In computer science, functional programming is a programming paradigm — a style of building the structure and elements of computer programs — that treats computation as the evaluation of mathematical functions and avoids changing- state and mutable data. It is a declarative programming paradigm, which means programming is done with expressions.” What is Functional Programming?

Slide 33

Slide 33 text

TL;DR Programming without assignment statements.

Slide 34

Slide 34 text

Key Concepts • Declarative (vs. Imperative) • First Class Functions • Referential Transparency and Purity • Recursion • Immutability • Partial Application and Currying • Composition

Slide 35

Slide 35 text

Thar be ES2015 ahead!

Slide 36

Slide 36 text

const greeting = 'hello'; let n = 42; n = 5; const add = (x, y) => x + y; const printAndReturn = (string) => { console.log(string); return string; }; function greet(g = 'Hi') { console.log(g); } function print(a, ...args) { console.log(a, ...args); } const [x, ...y] = ['foo', 'bar', 'baz']; console.log(x); // foo console.log(y); // ['bar', 'baz']

Slide 37

Slide 37 text

var greeting = 'hello'; const greeting = 'hello'; let n = 42; n = 5; const add = (x, y) => x + y; const printAndReturn = (string) => { console.log(string); return string; }; function greet(g = 'Hi') { console.log(g); } function print(a, ...args) { console.log(a, ...args); } const [x, ...y] = ['foo', 'bar', 'baz']; console.log(x); // foo console.log(y); // ['bar', 'baz']

Slide 38

Slide 38 text

var n = 42; n = 5; const greeting = 'hello'; let n = 42; n = 5; const add = (x, y) => x + y; const printAndReturn = (string) => { console.log(string); return string; }; function greet(g = 'Hi') { console.log(g); } function print(a, ...args) { console.log(a, ...args); } const [x, ...y] = ['foo', 'bar', 'baz']; console.log(x); // foo console.log(y); // ['bar', 'baz']

Slide 39

Slide 39 text

const greeting = 'hello'; let n = 42; n = 5; const add = (x, y) => x + y; const printAndReturn = (string) => { console.log(string); return string; }; function greet(g = 'Hi') { console.log(g); } function print(a, ...args) { console.log(a, ...args); } const [x, ...y] = ['foo', 'bar', 'baz']; console.log(x); // foo console.log(y); // ['bar', 'baz'] var add = function(x, y) { return x + y; }; var printAndReturn = function(string) { console.log(string); return string; };

Slide 40

Slide 40 text

const greeting = 'hello'; let n = 42; n = 5; const add = (x, y) => x + y; const printAndReturn = (string) => { console.log(string); return string; }; function greet(g = 'Hi') { console.log(g); } function print(a, ...args) { console.log(a, ...args); } const [x, ...y] = ['foo', 'bar', 'baz']; console.log(x); // foo console.log(y); // ['bar', 'baz'] function greet() { var g = arguments[0] === undefined ? 'Hi' : arguments[0]; console.log(g); }

Slide 41

Slide 41 text

const greeting = 'hello'; let n = 42; n = 5; const add = (x, y) => x + y; const printAndReturn = (string) => { console.log(string); return string; }; function greet(g = 'Hi') { console.log(g); } function print(a, ...args) { console.log(a, ...args); } const [x, ...y] = ['foo', 'bar', 'baz']; console.log(x); // foo console.log(y); // ['bar', 'baz'] function print(a) { var args = [].slice.call(arguments, 1); console.log.apply(console, [a],concat(args)); }

Slide 42

Slide 42 text

const greeting = 'hello'; let n = 42; n = 5; const add = (x, y) => x + y; const printAndReturn = (string) => { console.log(string); return string; }; function greet(g = 'Hi') { console.log(g); } function print(a, ...args) { console.log(a, ...args); } const [x, ...y] = ['foo', 'bar', 'baz']; console.log(x); // foo console.log(y); // ['bar', 'baz'] var _ref = ['foo', 'bar', 'baz']; var x = _ref[0]; var y = _ref.slice(1); console.log(x); console.log(y);

Slide 43

Slide 43 text

Declarative vs. Imperative

Slide 44

Slide 44 text

Imperative • Most familiar style of programming • Telling the computer how to accomplish a task • Algorithms are a series of steps • Mutable data usually involved • C, C++, Java

Slide 45

Slide 45 text

Imperative function doubleNumbers(numbers) { const doubled = []; const l = numbers.length; for (let i = 0; i < l; i++) { let doubledNumber = numbers[i] * 2; doubled.push(doubledNumber); } return doubled; } doubleNumbers([1, 2, 3]); // [2, 4, 6]

Slide 46

Slide 46 text

Imperative function doubleNumbers(numbers) { const doubled = []; const l = numbers.length; for (let i = 0; i < l; i++) { let doubledNumber = numbers[i] * 2; doubled.push(doubledNumber); } return doubled; } doubleNumbers([1, 2, 3]); // [2, 4, 6]

Slide 47

Slide 47 text

Imperative function doubleNumbers(numbers) { const doubled = []; const l = numbers.length; for (let i = 0; i < l; i++) { let doubledNumber = numbers[i] * 2; doubled.push(doubledNumber); } return doubled; } doubleNumbers([1, 2, 3]); // [2, 4, 6]

Slide 48

Slide 48 text

Imperative function doubleNumbers(numbers) { const doubled = []; const l = numbers.length; for (let i = 0; i < l; i++) { let doubledNumber = numbers[i] * 2; doubled.push(doubledNumber); } return doubled; } doubleNumbers([1, 2, 3]); // [2, 4, 6]

Slide 49

Slide 49 text

Imperative function doubleNumbers(numbers) { const doubled = []; const l = numbers.length; for (let i = 0; i < l; i++) { let doubledNumber = numbers[i] * 2; doubled.push(doubledNumber); } return doubled; } doubleNumbers([1, 2, 3]); // [2, 4, 6]

Slide 50

Slide 50 text

Declarative • Typically associated with functional programming • Telling the computer what you want, not how to get it • Algorithms are compositions of functions • Immutable data (or minimal side effects) preferred • SQL, HTML, Haskell, DSLs

Slide 51

Slide 51 text

Declarative function doubleNumber(n) { return n * 2; } function doubleNumbers(numbers) { return numbers.map(doubleNumber); } doubleNumbers([1, 2, 3]); // [2, 4, 6]

Slide 52

Slide 52 text

First Class Functions Functions are expressions/values.

Slide 53

Slide 53 text

First Class Functions Functions are expressions/values. // Function declaration function add(x, y) { return x + y; } // Assign to a variable const addAlias = add; // Assign an anonymous function expression const multiply = (x, y) => x * y; // Functions have properties console.log(add.name); // 'add' console.log(addAlias.name); // 'add' console.log(multiply.name); // ''

Slide 54

Slide 54 text

First Class Functions Functions are expressions/values. // Function declaration function add(x, y) { return x + y; } // Assign to a variable const addAlias = add; // Assign an anonymous function expression const multiply = (x, y) => x * y; // Functions have properties console.log(add.name); // 'add' console.log(addAlias.name); // 'add' console.log(multiply.name); // ''

Slide 55

Slide 55 text

First Class Functions Functions are expressions/values. // Function declaration function add(x, y) { return x + y; } // Assign to a variable const addAlias = add; // Assign an anonymous function expression const multiply = (x, y) => x * y; // Functions have properties console.log(add.name); // 'add' console.log(addAlias.name); // 'add' console.log(multiply.name); // ''

Slide 56

Slide 56 text

First Class Functions Functions are expressions/values. // Function declaration function add(x, y) { return x + y; } // Assign to a variable const addAlias = add; // Assign an anonymous function expression const multiply = (x, y) => x * y; // Functions have properties console.log(add.name); // 'add' console.log(addAlias.name); // 'add' console.log(multiply.name); // ''

Slide 57

Slide 57 text

First Class Functions Functions as arguments

Slide 58

Slide 58 text

First Class Functions Functions as arguments // Passing in anonymous functions myEventLib.on('update', (data) => console.log(data)); function doubleNumber(n) { return n * 2; } // Earlier example, passing in named function function doubleNumbers(numbers) { return numbers.map(doubleNumber); }

Slide 59

Slide 59 text

First Class Functions Functions as arguments // Passing in anonymous functions myEventLib.on('update', (data) => console.log(data)); function doubleNumber(n) { return n * 2; } // Earlier example, passing in named function function doubleNumbers(numbers) { return numbers.map(doubleNumber); }

Slide 60

Slide 60 text

First Class Functions Functions as return values

Slide 61

Slide 61 text

First Class Functions Functions as return values // Return a new function that adds a number // to another function additionFactory(x) { return (y) => x + y; } const add1 = additionFactory(1); add1(2); // 3

Slide 62

Slide 62 text

First Class Functions Functions as return values // Return a new function that adds a number // to another function additionFactory(x) { return (y) => x + y; } const add1 = additionFactory(1); add1(2); // 3

Slide 63

Slide 63 text

First Class Functions Functions as return values // Return a new function that adds a number // to another function additionFactory(x) { return (y) => x + y; } const add1 = additionFactory(1); add1(2); // 3

Slide 64

Slide 64 text

Closures

Slide 65

Slide 65 text

Closures • Allow functions to reference other scopes • “Close over” variables in higher scopes • Critical to functional programming paradigms like partial application

Slide 66

Slide 66 text

Closures // New function “closes” over x function additionFactory(x) { return (y) => x + y; } const add1 = additionFactory(1); add1(2); // 3

Slide 67

Slide 67 text

// New function “closes” over x function additionFactory(x) { return (y) => x + y; } const add1 = additionFactory(1); add1(2); // 3 Closures Same x

Slide 68

Slide 68 text

Closures let myValue = 'foo'; function closure() { console.log(myValue); } function trickyClosure() { let myValue = 'bar'; console.log(myValue); } function anotherTrickyClosure() { myValue = 'hello world'; console.log(myValue); } closure(); // 'foo' trickyClosure(); // 'bar' closure(); // 'foo' anotherTrickyClosure(); // 'hello world' closure(); // 'hello world' trickyClosure(); // 'bar'

Slide 69

Slide 69 text

Closures let myValue = 'foo'; function closure() { console.log(myValue); } function trickyClosure() { let myValue = 'bar'; console.log(myValue); } function anotherTrickyClosure() { myValue = 'hello world'; console.log(myValue); } closure(); // 'foo' trickyClosure(); // 'bar' closure(); // 'foo' anotherTrickyClosure(); // 'hello world' closure(); // 'hello world' trickyClosure(); // 'bar'

Slide 70

Slide 70 text

let myValue = 'foo'; function closure() { console.log(myValue); } function trickyClosure() { let myValue = 'bar'; console.log(myValue); } function anotherTrickyClosure() { myValue = 'hello world'; console.log(myValue); } closure(); // 'foo' trickyClosure(); // 'bar' closure(); // 'foo' anotherTrickyClosure(); // 'hello world' closure(); // 'hello world' trickyClosure(); // 'bar' Closures

Slide 71

Slide 71 text

Closures let myValue = 'foo'; function closure() { console.log(myValue); } function trickyClosure() { let myValue = 'bar'; console.log(myValue); } function anotherTrickyClosure() { myValue = 'hello world'; console.log(myValue); } closure(); // 'foo' trickyClosure(); // 'bar' closure(); // 'foo' anotherTrickyClosure(); // 'hello world' closure(); // 'hello world' trickyClosure(); // 'bar'

Slide 72

Slide 72 text

Closures let myValue = 'foo'; // Becomes 'hello world' function closure() { console.log(myValue); } function trickyClosure() { let myValue = 'bar'; console.log(myValue); } function anotherTrickyClosure() { myValue = 'hello world'; console.log(myValue); } closure(); // 'foo' trickyClosure(); // 'bar' closure(); // 'foo' anotherTrickyClosure(); // 'hello world' closure(); // 'hello world' trickyClosure(); // 'bar'

Slide 73

Slide 73 text

Closures let myValue = 'foo'; // Now 'hello world' function closure() { console.log(myValue); } function trickyClosure() { let myValue = 'bar'; console.log(myValue); } function anotherTrickyClosure() { myValue = 'hello world'; console.log(myValue); } closure(); // 'foo' trickyClosure(); // 'bar' closure(); // 'foo' anotherTrickyClosure(); // 'hello world' closure(); // 'hello world' trickyClosure(); // 'bar'

Slide 74

Slide 74 text

Closures let myValue = 'foo'; // Now 'hello world' function closure() { console.log(myValue); } function trickyClosure() { let myValue = 'bar'; console.log(myValue); } function anotherTrickyClosure() { myValue = 'hello world'; console.log(myValue); } closure(); // 'foo' trickyClosure(); // 'bar' closure(); // 'foo' anotherTrickyClosure(); // 'hello world' closure(); // 'hello world' trickyClosure(); // 'bar'

Slide 75

Slide 75 text

Referential Transparency

Slide 76

Slide 76 text

Referential Transparency • Fuzzy term associated with purity • For a given input, a function always returns the same value • Replace function calls with return value • No dependency on state outside function

Slide 77

Slide 77 text

Referential Transparency function doubleNumber(n) { return n * 2; } function square(n) { return n * n; } function add6(n) { return n + 6; } // Reduces down to the same value let value1 = add6(square(doubleNumber(3))); // 42 let value2 = add6(square(6)); // 42 let value3 = add6(36); // 42 let value4 = 42; // Same value for every call let otherValue1 = doubleNumber(3) + doubleNumber(3) + doubleNumber(3) + doubleNumber(3); let otherValue2 = 6 + 6 + 6 + 6;

Slide 78

Slide 78 text

Referential Transparency function doubleNumber(n) { return n * 2; } function square(n) { return n * n; } function add6(n) { return n + 6; } // Reduces down to the same value let value1 = add6(square(doubleNumber(3))); // 42 let value2 = add6(square(6)); // 42 let value3 = add6(36); // 42 let value4 = 42; // Same value for every call let otherValue1 = doubleNumber(3) + doubleNumber(3) + doubleNumber(3) + doubleNumber(3); let otherValue2 = 6 + 6 + 6 + 6;

Slide 79

Slide 79 text

Referential Transparency function doubleNumber(n) { return n * 2; } function square(n) { return n * n; } function add6(n) { return n + 6; } // Reduces down to the same value let value1 = add6(square(doubleNumber(3))); // 42 let value2 = add6(square(6)); // 42 let value3 = add6(36); // 42 let value4 = 42; // Same value for every call let otherValue1 = doubleNumber(3) + doubleNumber(3) + doubleNumber(3) + doubleNumber(3); let otherValue2 = 6 + 6 + 6 + 6;

Slide 80

Slide 80 text

Referential Transparency let counter = 0; function addToCounter1(n) { counter++; return n + counter; } function addToCounter2(n) { let counter = 0; counter++; return n + counter; } // Not referentially transparent let value1 = addToCounter1(1) + addToCounter1(1); // 5 let value2 = 2 + 3; // Not the same value every call! // Referentially transparent let otherValue1 = addToCounter2(1) + addToCounter2(1); // 4 let otherValue2 = 2 + 2;

Slide 81

Slide 81 text

Referential Transparency let counter = 0; function addToCounter1(n) { counter++; return n + counter; } function addToCounter2(n) { let counter = 0; counter++; return n + counter; } // Not referentially transparent let value1 = addToCounter1(1) + addToCounter1(1); // 5 let value2 = 2 + 3; // Not the same value every call! // Referentially transparent let otherValue1 = addToCounter2(1) + addToCounter2(1); // 4 let otherValue2 = 2 + 2;

Slide 82

Slide 82 text

Referential Transparency let counter = 0; function addToCounter1(n) { counter++; return n + counter; } function addToCounter2(n) { let counter = 0; counter++; return n + counter; } // Not referentially transparent let value1 = addToCounter1(1) + addToCounter1(1); // 5 let value2 = 2 + 3; // Not the same value every call! // Referentially transparent let otherValue1 = addToCounter2(1) + addToCounter2(1); // 4 let otherValue2 = 2 + 2;

Slide 83

Slide 83 text

Idempotency

Slide 84

Slide 84 text

Idempotency • Special case of referential transparency • Multiple function applications produce the same result as one application

Slide 85

Slide 85 text

Idempotency let abs = Math.abs; function identity(x) { return x; } function add2(n) { return n + 2; } // Idempotent and referentially transparent abs(abs(abs(abs(-1)))) === abs(-1); identity(identity(identity(42))) === identity(42); // Not idempotent, but referentially transparent add2(add2(add2(1))) !== add2(1); // 7 !== 3

Slide 86

Slide 86 text

Idempotency let abs = Math.abs; function identity(x) { return x; } function add2(n) { return n + 2; } // Idempotent and referentially transparent abs(abs(abs(abs(-1)))) === abs(-1); identity(identity(identity(42))) === identity(42); // Not idempotent, but referentially transparent add2(add2(add2(1))) !== add2(1); // 7 !== 3

Slide 87

Slide 87 text

Idempotency let abs = Math.abs; function identity(x) { return x; } function add2(n) { return n + 2; } // Idempotent and referentially transparent abs(abs(abs(abs(-1)))) === abs(-1); identity(identity(identity(42))) === identity(42); // Not idempotent, but referentially transparent add2(add2(add2(1))) !== add2(1); // 7 !== 3

Slide 88

Slide 88 text

Purity

Slide 89

Slide 89 text

Purity • “Strict referential transparency” • No side effects • No global/shared state • No impure arguments • No I/O

Slide 90

Slide 90 text

Pure Functions function add(x, y) { return x + y; } function capitalize(string) { return string[0].toUpperCase() + string.slice(1).toLowerCase(); } function toTitleCase(string) { return string .split(/\s+/) .map(capitalize) .join(' '); }

Slide 91

Slide 91 text

Pure Functions function add(x, y) { return x + y; } function capitalize(string) { return string[0].toUpperCase() + string.slice(1).toLowerCase(); } function toTitleCase(string) { return string .split(/\s+/) .map(capitalize) .join(' '); }

Slide 92

Slide 92 text

Pure Functions function add(x, y) { return x + y; } function capitalize(string) { return string[0].toUpperCase() + string.slice(1).toLowerCase(); } function toTitleCase(string) { return string .split(/\s+/) .map(capitalize) .join(' '); }

Slide 93

Slide 93 text

Pure Functions function add(x, y) { return x + y; } function capitalize(string) { return string[0].toUpperCase() + string.slice(1).toLowerCase(); } function toTitleCase(string) { return string .split(/\s+/) .map(capitalize) .join(' '); }

Slide 94

Slide 94 text

Pure Functions function add(x, y) { return x + y; } function capitalize(string) { return string[0].toUpperCase() + string.slice(1).toLowerCase(); } function toTitleCase(string) { return string .split(/\s+/) .map(capitalize) .join(' '); } • No side effects. • String and number arguments are immutable.

Slide 95

Slide 95 text

Impure Functions let myName = 'Jeremy'; const myHobbies = ['programming', 'reading', 'playing guitar']; function getName() { return myName; } function printName(name) { console.log(name); } function add(x, y) { myName = 'Joe'; return x + y; } function hobbiesMapper(hobbies) { return (fn) => hobbies.map(fn); }

Slide 96

Slide 96 text

let myName = 'Jeremy'; const myHobbies = ['programming', 'reading', 'playing guitar']; function getName() { return myName; } function printName(name) { console.log(name); } function add(x, y) { myName = 'Joe'; return x + y; } function hobbiesMapper(hobbies) { return (fn) => hobbies.map(fn); } Impure Functions Accesses global state

Slide 97

Slide 97 text

let myName = 'Jeremy'; const myHobbies = ['programming', 'reading', 'playing guitar']; function getName() { return myName; } function printName(name) { console.log(name); } function add(x, y) { myName = 'Joe'; return x + y; } function hobbiesMapper(hobbies) { return (fn) => hobbies.map(fn); } Impure Functions Prints to stdout

Slide 98

Slide 98 text

let myName = 'Jeremy'; const myHobbies = ['programming', 'reading', 'playing guitar']; function getName() { return myName; } function printName(name) { console.log(name); } function add(x, y) { myName = 'Joe'; return x + y; } function hobbiesMapper(hobbies) { return (fn) => hobbies.map(fn); } Impure Functions Modifies global state

Slide 99

Slide 99 text

let myName = 'Jeremy'; const myHobbies = ['programming', 'reading', 'playing guitar']; function getName() { return myName; } function printName(name) { console.log(name); } function add(x, y) { myName = 'Joe'; return x + y; } function hobbiesMapper(hobbies) { return (fn) => hobbies.map(fn); } Impure Functions Array may mutate

Slide 100

Slide 100 text

Recursion

Slide 101

Slide 101 text

Recursion • Defining a solution to a problem in terms of itself • Solve the problem by solving smaller pieces • Similar to inductive proofs • In programming, a function that calls itself • In FP, imperative looping (e.g. with while or for) is practically nonexistent, so solve with recursion

Slide 102

Slide 102 text

Recursion: Factorial

Slide 103

Slide 103 text

Recursion: Factorial function factorial(n) { let result = 1; while (n > 1) { result *= n--; } return result; } Imperative

Slide 104

Slide 104 text

Recursion: Factorial function factorial(n) { let result = 1; while (n > 1) { result *= n--; } return result; } Imperative function factorial(n) { if (n < 2) { return 1; } return n * factorial(n - 1); } Recursive

Slide 105

Slide 105 text

Recursion: Factorial function factorial(n) { if (n < 2) { return 1; } return n * factorial(n - 1); }

Slide 106

Slide 106 text

Recursion: Factorial function factorial(n) { if (n < 2) { return 1; } return n * factorial(n - 1); } Base case

Slide 107

Slide 107 text

Recursion: Factorial function factorial(n) { if (n < 2) { return 1; } return n * factorial(n - 1); } Recursive call

Slide 108

Slide 108 text

Recursion: Factorial

Slide 109

Slide 109 text

Recursion: Factorial factorial(4);

Slide 110

Slide 110 text

Recursion: Factorial factorial(4); 4 * factorial(3);

Slide 111

Slide 111 text

Recursion: Factorial factorial(4); 4 * factorial(3); 4 * 3 * factorial(2);

Slide 112

Slide 112 text

Recursion: Factorial factorial(4); 4 * factorial(3); 4 * 3 * factorial(2); 4 * 3 * 2 * factorial(1);

Slide 113

Slide 113 text

Recursion: Factorial factorial(4); 4 * factorial(3); 4 * 3 * factorial(2); 4 * 3 * 2 * factorial(1); 4 * 3 * 2 * 1;

Slide 114

Slide 114 text

Recursion: Factorial factorial(4); 4 * factorial(3); 4 * 3 * factorial(2); 4 * 3 * 2 * factorial(1); 4 * 3 * 2 * 1; 4 * 3 * 2;

Slide 115

Slide 115 text

Recursion: Factorial factorial(4); 4 * factorial(3); 4 * 3 * factorial(2); 4 * 3 * 2 * factorial(1); 4 * 3 * 2 * 1; 4 * 3 * 2; 4 * 6;

Slide 116

Slide 116 text

Recursion: Factorial factorial(4); 4 * factorial(3); 4 * 3 * factorial(2); 4 * 3 * 2 * factorial(1); 4 * 3 * 2 * 1; 4 * 3 * 2; 4 * 6; 24;

Slide 117

Slide 117 text

What about recursion performance?

Slide 118

Slide 118 text

Recursion Performance let value = factorial(100000); console.log(value); // ???

Slide 119

Slide 119 text

Recursion Performance let value = factorial(100000); console.log(value); // ??? RangeError: Maximum call stack size exceeded

Slide 120

Slide 120 text

Recursion: Factorial function factorial(n) { if (n < 2) { return 1; } return n * factorial(n - 1); }

Slide 121

Slide 121 text

Recursion: Factorial function factorial(n) { if (n < 2) { return 1; } return n * factorial(n - 1); }

Slide 122

Slide 122 text

Recursion: Factorial factorial(4); 4 * factorial(3); 4 * 3 * factorial(2); 4 * 3 * 2 * factorial(1); 4 * 3 * 2 * 1; 4 * 3 * 2; 4 * 6; 24;

Slide 123

Slide 123 text

Recursion: Factorial factorial(4); 4 * factorial(3); 4 * 3 * factorial(2); 4 * 3 * 2 * factorial(1); 4 * 3 * 2 * 1; 4 * 3 * 2; 4 * 6; 24; Stack

Slide 124

Slide 124 text

Recursion: Factorial factorial(4); 4 * factorial(3); 4 * 3 * factorial(2); 4 * 3 * 2 * factorial(1); 4 * 3 * 2 * 1; 4 * 3 * 2; 4 * 6; 24; factorial(4) Stack

Slide 125

Slide 125 text

Recursion: Factorial factorial(4) factorial(3) factorial(4); 4 * factorial(3); 4 * 3 * factorial(2); 4 * 3 * 2 * factorial(1); 4 * 3 * 2 * 1; 4 * 3 * 2; 4 * 6; 24; Stack

Slide 126

Slide 126 text

Recursion: Factorial factorial(4) factorial(3) factorial(4); 4 * factorial(3); 4 * 3 * factorial(2); 4 * 3 * 2 * factorial(1); 4 * 3 * 2 * 1; 4 * 3 * 2; 4 * 6; 24; factorial(2) Stack

Slide 127

Slide 127 text

Recursion: Factorial factorial(4) factorial(3) factorial(4); 4 * factorial(3); 4 * 3 * factorial(2); 4 * 3 * 2 * factorial(1); 4 * 3 * 2 * 1; 4 * 3 * 2; 4 * 6; 24; factorial(2) factorial(1) Stack

Slide 128

Slide 128 text

Recursion: Factorial factorial(4) factorial(3) factorial(2) factorial(4); 4 * factorial(3); 4 * 3 * factorial(2); 4 * 3 * 2 * factorial(1); 4 * 3 * 2 * 1; 4 * 3 * 2; 4 * 6; 24; Stack

Slide 129

Slide 129 text

Recursion: Factorial factorial(4) factorial(3) factorial(4); 4 * factorial(3); 4 * 3 * factorial(2); 4 * 3 * 2 * factorial(1); 4 * 3 * 2 * 1; 4 * 3 * 2; 4 * 6; 24; Stack

Slide 130

Slide 130 text

Recursion: Factorial factorial(4) factorial(4); 4 * factorial(3); 4 * 3 * factorial(2); 4 * 3 * 2 * factorial(1); 4 * 3 * 2 * 1; 4 * 3 * 2; 4 * 6; 24; Stack

Slide 131

Slide 131 text

Recursion: Factorial factorial(4); 4 * factorial(3); 4 * 3 * factorial(2); 4 * 3 * 2 * factorial(1); 4 * 3 * 2 * 1; 4 * 3 * 2; 4 * 6; 24; Stack

Slide 132

Slide 132 text

Recursion Performance let value = factorial(100000); console.log(value); // ??? 100,000 calls = 100,000 stack frames 1 stack frame ≈ 48b Max stack usage ≈ 1mb 100,000 × 48 / 1024 / 1024 = 4.58mb > 1mb

Slide 133

Slide 133 text

Tail call optimization to the rescue!

Slide 134

Slide 134 text

Tail Call Optimization

Slide 135

Slide 135 text

Tail Call Optimization • Optimize recursive functions to not exhaust max stack size • Replace stack frames instead of adding new ones • The last statement before returning must be recursive call • Typically rewrite function to include an accumulator that holds the current result • (Coming to JavaScript in ES2015!)

Slide 136

Slide 136 text

Tail Call Optimization Unoptimizable function factorial(n) { if (n < 2) { return 1; } return n * factorial(n - 1); }

Slide 137

Slide 137 text

Tail Call Optimization Unoptimizable function factorial(n) { if (n < 2) { return 1; } return n * factorial(n - 1); } 1

Slide 138

Slide 138 text

Tail Call Optimization Unoptimizable function factorial(n) { if (n < 2) { return 1; } return n * factorial(n - 1); } 1 2

Slide 139

Slide 139 text

Tail Call Optimization Unoptimizable function factorial(n) { if (n < 2) { return 1; } return n * factorial(n - 1); } 1 3 2

Slide 140

Slide 140 text

Optimize Factorial function factorial(n, accum = 1) { if (n < 2) { return accum; } return factorial(n - 1, n * accum); }

Slide 141

Slide 141 text

Optimize Factorial function factorial(n, accum = 1) { if (n < 2) { return accum; } return factorial(n - 1, n * accum); } Current value accumulator

Slide 142

Slide 142 text

Optimize Factorial function factorial(n, accum = 1) { if (n < 2) { return accum; } return factorial(n - 1, n * accum); } Return the accumulator for base case

Slide 143

Slide 143 text

Optimize Factorial function factorial(n, accum = 1) { if (n < 2) { return accum; } return factorial(n - 1, n * accum); } Move calculation inside the call

Slide 144

Slide 144 text

Optimize Factorial function factorial(n, accum = 1) { if (n < 2) { return accum; } return factorial(n - 1, n * accum); } 1

Slide 145

Slide 145 text

Optimize Factorial function factorial(n, accum = 1) { if (n < 2) { return accum; } return factorial(n - 1, n * accum); } 1 2

Slide 146

Slide 146 text

Optimize Factorial function factorial(n, accum = 1) { if (n < 2) { return accum; } return factorial(n - 1, n * accum); } 1 3 2

Slide 147

Slide 147 text

And now? let value = factorial(100000); console.log(value); // Infinity

Slide 148

Slide 148 text

Factorial TCO factorial(4 /*, 1 */); factorial(3, 4); factorial(2, 12); factorial(1, 24); 24;

Slide 149

Slide 149 text

Factorial TCO factorial(4 /*, 1 */); factorial(3, 4); factorial(2, 12); factorial(1, 24); 24; Stack

Slide 150

Slide 150 text

Factorial TCO factorial(4, 1) Stack factorial(4 /*, 1 */); factorial(3, 4); factorial(2, 12); factorial(1, 24); 24;

Slide 151

Slide 151 text

Factorial TCO factorial(3, 4) Stack factorial(4 /*, 1 */); factorial(3, 4); factorial(2, 12); factorial(1, 24); 24;

Slide 152

Slide 152 text

Factorial TCO factorial(2, 12) Stack factorial(4 /*, 1 */); factorial(3, 4); factorial(2, 12); factorial(1, 24); 24;

Slide 153

Slide 153 text

Factorial TCO factorial(1, 24) Stack factorial(4 /*, 1 */); factorial(3, 4); factorial(2, 12); factorial(1, 24); 24;

Slide 154

Slide 154 text

Factorial TCO Stack factorial(4 /*, 1 */); factorial(3, 4); factorial(2, 12); factorial(1, 24); 24;

Slide 155

Slide 155 text

Recursion: Fibonacci

Slide 156

Slide 156 text

Recursion: Fibonacci

Slide 157

Slide 157 text

Recursion: Fibonacci Base cases

Slide 158

Slide 158 text

Recursion: Fibonacci Recurrence

Slide 159

Slide 159 text

Recursion: Fibonacci function fibonacci(n) { if (n < 2) { return n; } return fibonacci(n - 1) + fibonacci(n - 2); }

Slide 160

Slide 160 text

Recursion: Fibonacci function fibonacci(n) { if (n < 2) { return n; } return fibonacci(n - 1) + fibonacci(n - 2); } Base Cases

Slide 161

Slide 161 text

Recursion: Fibonacci function fibonacci(n) { if (n < 2) { return n; } return fibonacci(n - 1) + fibonacci(n - 2); } Recurrence

Slide 162

Slide 162 text

Recursion: Fibonacci fib(0); // 0 fib(1); // 1 fib(2); // 1 fib(3); // 2 fib(4); // 3 fib(5); // 5 function fibonacci(n) { if (n < 2) { return n; } return fibonacci(n - 1) + fibonacci(n - 2); }

Slide 163

Slide 163 text

Performance Revisited fibonacci(1); // 0 ms

Slide 164

Slide 164 text

Performance Revisited fibonacci(1); // 0 ms fibonacci(5); // 0 ms

Slide 165

Slide 165 text

Performance Revisited fibonacci(1); // 0 ms fibonacci(5); // 0 ms fibonacci(20); // 0 ms

Slide 166

Slide 166 text

Performance Revisited fibonacci(1); // 0 ms fibonacci(5); // 0 ms fibonacci(20); // 0 ms fibonacci(30); // 13 ms

Slide 167

Slide 167 text

Performance Revisited fibonacci(1); // 0 ms fibonacci(5); // 0 ms fibonacci(20); // 0 ms fibonacci(30); // 13 ms fibonacci(35); // 131 ms

Slide 168

Slide 168 text

Performance Revisited fibonacci(1); // 0 ms fibonacci(5); // 0 ms fibonacci(20); // 0 ms fibonacci(30); // 13 ms fibonacci(35); // 131 ms fibonacci(40); // 1516 ms

Slide 169

Slide 169 text

Performance Revisited fibonacci(1); // 0 ms fibonacci(5); // 0 ms fibonacci(20); // 0 ms fibonacci(30); // 13 ms fibonacci(35); // 131 ms fibonacci(40); // 1516 ms fibonacci(45); // 16.6 seconds!

Slide 170

Slide 170 text

Performance Revisited fibonacci(1); // 0 ms fibonacci(5); // 0 ms fibonacci(20); // 0 ms fibonacci(30); // 13 ms fibonacci(35); // 131 ms fibonacci(40); // 1516 ms fibonacci(45); // 16.6 seconds! fibonacci(100); // Who knows how long

Slide 171

Slide 171 text

Exponential Growth Runtime (ms) 0 4500 9000 13500 18000 Nth number of Fibonacci Sequence 0 10 20 30 40 50

Slide 172

Slide 172 text

Recursive Call Tree

Slide 173

Slide 173 text

Recursive Call Tree Computing some of the same values several times!

Slide 174

Slide 174 text

Recursive Call Tree Computing some of the same values several times! fibonacci(4) x 2

Slide 175

Slide 175 text

Recursive Call Tree Computing some of the same values several times! fibonacci(4) x 2 fibonacci(3) x 3

Slide 176

Slide 176 text

Recursive Call Tree Computing some of the same values several times! fibonacci(4) x 2 fibonacci(3) x 3 fibonacci(2) x 5

Slide 177

Slide 177 text

Recursive Call Tree Computing some of the same values several times! fibonacci(4) x 2 fibonacci(3) x 3 fibonacci(2) x 5 fibonacci(1) x 3

Slide 178

Slide 178 text

TCO and Dynamic Programming

Slide 179

Slide 179 text

TCO and Dynamic Programming • Build up the result from the leaves of the tree • Avoids recalculating the same values • Make recursive calls in the reverse direction

Slide 180

Slide 180 text

Fibonacci TCO function fibonacci(n, current = 0, next = 1) { if (n === 0) { return current; } return fibonacci(n - 1, next, current + next); }

Slide 181

Slide 181 text

Fibonacci TCO function fibonacci(n, current = 0, next = 1) { if (n === 0) { return current; } return fibonacci(n - 1, next, current + next); } Two accumulators

Slide 182

Slide 182 text

Fibonacci TCO function fibonacci(n, current = 0, next = 1) { if (n === 0) { return current; } return fibonacci(n - 1, next, current + next); } Results for next call

Slide 183

Slide 183 text

Fibonacci TCO function fibonacci(n, current = 0, next = 1) { if (n === 0) { return current; } return fibonacci(n - 1, next, current + next); } Reach the end, so return whatever was built up

Slide 184

Slide 184 text

Fibonacci TCO fibonacci(6 /*, 0, 1 */); fibonacci(5, 1, 1); fibonacci(4, 1, 2); fibonacci(3, 2, 3); fibonacci(2, 3, 5); fibonacci(1, 5, 8); fibonacci(0, 8, 13); 8;

Slide 185

Slide 185 text

Fibonacci TCO fibonacci(6 /*, 0, 1 */); fibonacci(5, 1, 1); fibonacci(4, 1, 2); fibonacci(3, 2, 3); fibonacci(2, 3, 5); fibonacci(1, 5, 8); fibonacci(0, 8, 13); 8; Fibonacci sequence

Slide 186

Slide 186 text

Fibonacci Performance fibonacci(1); // 0 ms fibonacci(5); // 0 ms fibonacci(20); // 0 ms fibonacci(30); // 0 ms fibonacci(35); // 0 ms fibonacci(40); // 0 ms fibonacci(45); // 0 ms fibonacci(100); // 0 ms

Slide 187

Slide 187 text

Functional Arrays

Slide 188

Slide 188 text

Functional Arrays • Common operations like map can be implemented in FP • Enforce immutability by returning new array • No looping; use recursion!

Slide 189

Slide 189 text

Array#map Map values in array to other values in new array function map(fn, array) { if (array.length === 0) { return array; } const [head, ...tail] = array; return [fn(head), ...map(fn, tail)]; }

Slide 190

Slide 190 text

Array#map Map values in array to other values in new array function map(fn, array) { if (array.length === 0) { return array; } const [head, ...tail] = array; return [fn(head), ...map(fn, tail)]; } Function first; good for currying

Slide 191

Slide 191 text

Array#map Map values in array to other values in new array function map(fn, array) { if (array.length === 0) { return array; } const [head, ...tail] = array; return [fn(head), ...map(fn, tail)]; } Grab the first element and remaining elements

Slide 192

Slide 192 text

function map(fn, array) { if (array.length === 0) { return array; } const [head, ...tail] = array; return [fn(head), ...map(fn, tail)]; } Array#map Map values in array to other values in new array var head = array[0];

Slide 193

Slide 193 text

function map(fn, array) { if (array.length === 0) { return array; } const [head, ...tail] = array; return [fn(head), ...map(fn, tail)]; } Array#map Map values in array to other values in new array var tail = array.slice(1);

Slide 194

Slide 194 text

Array#map Map values in array to other values in new array function map(fn, array) { if (array.length === 0) { return array; } const [head, ...tail] = array; return [fn(head), ...map(fn, tail)]; } Return new array with altered head and mapped array of remaining elements

Slide 195

Slide 195 text

Array#map Map values in array to other values in new array function map(fn, array) { if (array.length === 0) { return array; } const [head, ...tail] = array; return [fn(head), ...map(fn, tail)]; } return [fn(head)].concat(map(fn, tail));

Slide 196

Slide 196 text

Array#map Map values in array to other values in new array function map(fn, array) { if (array.length === 0) { return array; } const [head, ...tail] = array; return [fn(head), ...map(fn, tail)]; } Base case: empty array.

Slide 197

Slide 197 text

Array#map Map values in array to other values in new array function square(n) { return n * n; } let numbers = [1, 2, 3]; let squaredNumbers = map(square, numbers); // [1, 4, 9];

Slide 198

Slide 198 text

Partial Application

Slide 199

Slide 199 text

Partial Application • Assign values to function parameters without evaluating the function (i.e. “prefill” argument values) • Produce a new function that takes in any remaining unassigned arguments

Slide 200

Slide 200 text

Partial Application // Before we would use this function additionFactory(x) { return (y) => x + y; } let add1 = additionFactory(1); add1(2); // 3 // Now we can write an add function // and use partial application function add(x, y) { return x + y; } // Partial application with native `bind` function add1 = add.bind(null, 1); add1(2); // 3 // Use a custom-written `partial` function add1 = partial(add, 1); add1(2); // 3

Slide 201

Slide 201 text

Partial Application // Before we would use this function additionFactory(x) { return (y) => x + y; } let add1 = additionFactory(1); add1(2); // 3 // Now we can write an add function // and use partial application function add(x, y) { return x + y; } // Partial application with native `bind` function add1 = add.bind(null, 1); add1(2); // 3 // Use a custom-written `partial` function add1 = partial(add, 1); add1(2); // 3

Slide 202

Slide 202 text

Partial Application // Before we would use this function additionFactory(x) { return (y) => x + y; } let add1 = additionFactory(1); add1(2); // 3 // Now we can write an add function // and use partial application function add(x, y) { return x + y; } // Partial application with native `bind` function add1 = add.bind(null, 1); add1(2); // 3 // Use a custom-written `partial` function add1 = partial(add, 1); add1(2); // 3

Slide 203

Slide 203 text

Partial Application // Before we would use this function additionFactory(x) { return (y) => x + y; } let add1 = additionFactory(1); add1(2); // 3 // Now we can write an add function // and use partial application function add(x, y) { return x + y; } // Partial application with native `bind` function add1 = add.bind(null, 1); add1(2); // 3 // Use a custom-written `partial` function add1 = partial(add, 1); add1(2); // 3

Slide 204

Slide 204 text

Partial Application function partial(fn, ...args) { return (...otherArgs) => { return fn(...args, ...otherArgs); }; }

Slide 205

Slide 205 text

Partial Application function partial(fn, ...args) { return (...otherArgs) => { return fn(...args, ...otherArgs); }; } Applied arguments

Slide 206

Slide 206 text

Partial Application function partial(fn, ...args) { return (...otherArgs) => { return fn(...args, ...otherArgs); }; } Return new closure

Slide 207

Slide 207 text

Partial Application function partial(fn, ...args) { return (...otherArgs) => { return fn(...args, ...otherArgs); }; } Remaining arguments

Slide 208

Slide 208 text

Partial Application function partial(fn, ...args) { return (...otherArgs) => { return fn(...args, ...otherArgs); }; } Call original function with all arguments

Slide 209

Slide 209 text

Partial Application: Why? • Build up functions from smaller pieces • Remove duplication • Generalize function abstraction (i.e. no additionFactory type functions)

Slide 210

Slide 210 text

Partial Application: Why? function multiply(x, y) { return x * y; } const doubleNumber = partial(multiply, 2); const numbers = [1, 2, 3]; const doubledNumbers = map(doubleNumber, numbers); console.log(doubledNumbers); // [2, 4, 6]

Slide 211

Slide 211 text

Currying

Slide 212

Slide 212 text

Currying • Similar to partial application • Bakes partial application into a function • Successive invocations of function with arguments returns a new function with those arguments assigned • Keep returning a new function until all arguments “filled,” and then invoke the actual function with all of those arguments (sounds recursive, huh?)

Slide 213

Slide 213 text

Currying const add = curry((x, y, z) => x + y + z); // All arguments supplied, normal invocation. add(1, 2, 3); // 6 // Supply arguments one at a time. Final argument // induces invocation. add(1)(2)(3); // 6 // Equivalent to previous example. let add1 = add(1); let add3 = add1(2); add3(3); // 6 // Supply more than one argument at a time. add(1, 2)(3); // 6 add(1)(2, 3); // 6

Slide 214

Slide 214 text

Currying const add = curry((x, y, z) => x + y + z); // All arguments supplied, normal invocation. add(1, 2, 3); // 6 // Supply arguments one at a time. Final argument // induces invocation. add(1)(2)(3); // 6 // Equivalent to previous example. let add1 = add(1); let add3 = add1(2); add3(3); // 6 // Supply more than one argument at a time. add(1, 2)(3); // 6 add(1)(2, 3); // 6

Slide 215

Slide 215 text

Currying const add = curry((x, y, z) => x + y + z); // All arguments supplied, normal invocation. add(1, 2, 3); // 6 // Supply arguments one at a time. Final argument // induces invocation. add(1)(2)(3); // 6 // Equivalent to previous example. let add1 = add(1); let add3 = add1(2); add3(3); // 6 // Supply more than one argument at a time. add(1, 2)(3); // 6 add(1)(2, 3); // 6

Slide 216

Slide 216 text

Currying const add = curry((x, y, z) => x + y + z); // All arguments supplied, normal invocation. add(1, 2, 3); // 6 // Supply arguments one at a time. Final argument // induces invocation. add(1)(2)(3); // 6 // Equivalent to previous example. let add1 = add(1); let add3 = add1(2); add3(3); // 6 // Supply more than one argument at a time. add(1, 2)(3); // 6 add(1)(2, 3); // 6

Slide 217

Slide 217 text

Currying const add = curry((x, y, z) => x + y + z); // All arguments supplied, normal invocation. add(1, 2, 3); // 6 // Supply arguments one at a time. Final argument // induces invocation. add(1)(2)(3); // 6 // Equivalent to previous example. let add1 = add(1); let add3 = add1(2); add3(3); // 6 // Supply more than one argument at a time. add(1, 2)(3); // 6 add(1)(2, 3); // 6

Slide 218

Slide 218 text

Currying const add = curry((x, y, z) => x + y + z); // All arguments supplied, normal invocation. add(1, 2, 3); // 6 // Supply arguments one at a time. Final argument // induces invocation. add(1)(2)(3); // 6 // Equivalent to previous example. let add1 = add(1); let add3 = add1(2); add3(3); // 6 // Supply more than one argument at a time. add(1, 2)(3); // 6 add(1)(2, 3); // 6

Slide 219

Slide 219 text

Currying function curry(fn, len = fn.length) { return (...args) => { if (args.length >= len) { return fn(...args); } return curry( partial(fn, ...args), len - args.length ); }; }

Slide 220

Slide 220 text

Currying function curry(fn, len = fn.length) { return (...args) => { if (args.length >= len) { return fn(...args); } return curry( partial(fn, ...args), len - args.length ); }; } Knowing arity is important!

Slide 221

Slide 221 text

Currying function curry(fn, len = fn.length) { return (...args) => { if (args.length >= len) { return fn(...args); } return curry( partial(fn, ...args), len - args.length ); }; } Arguments to apply (or invoke)

Slide 222

Slide 222 text

Currying function curry(fn, len = fn.length) { return (...args) => { if (args.length >= len) { return fn(...args); } return curry( partial(fn, ...args), len - args.length ); }; } Recursive call if not all arguments supplied

Slide 223

Slide 223 text

Currying function curry(fn, len = fn.length) { return (...args) => { if (args.length >= len) { return fn(...args); } return curry( partial(fn, ...args), len - args.length ); }; } Curry the partially applied function

Slide 224

Slide 224 text

Currying function curry(fn, len = fn.length) { return (...args) => { if (args.length >= len) { return fn(...args); } return curry( partial(fn, ...args), len - args.length ); }; } Arity decreases

Slide 225

Slide 225 text

Currying function curry(fn, len = fn.length) { return (...args) => { if (args.length >= len) { return fn(...args); } return curry( partial(fn, ...args), len - args.length ); }; } Base case: all arguments supplied

Slide 226

Slide 226 text

Currying: Why? let curriedMap = curry(map); let multiply = curry((x, y) => x * y); let doubleNumbers = curriedMap(multiply(2)); let numbers = [1, 2, 3]; console.log(doubleNumbers(numbers)); // [2, 4, 6]

Slide 227

Slide 227 text

Function Composition

Slide 228

Slide 228 text

Function Composition

Slide 229

Slide 229 text

Function Composition • Compose functions together to form new functions • Pipe function output to next function • Helps enforce modularity/ SOC by keeping functions small

Slide 230

Slide 230 text

Function Composition let multiply = curry((x, y) => x * y); let multiply2 = multiply(2); let multiply3 = multiply(3); let multiply6 = compose(multiply2, multiply3); 2 * 3 * 6 === multiply6(6); // 36 let add = curry((x, y) => x + y); let subtract = curry((y, x) => -y + x); let add5 = compose(add(6), add(1), subtract(2)); 3 - 2 + 6 + 1 === add5(3); // 8

Slide 231

Slide 231 text

Function Composition let multiply = curry((x, y) => x * y); let multiply2 = multiply(2); let multiply3 = multiply(3); let multiply6 = compose(multiply2, multiply3); 2 * 3 * 6 === multiply6(6); // 36 let add = curry((x, y) => x + y); let subtract = curry((y, x) => -y + x); let add5 = compose(add(6), add(1), subtract(2)); 3 - 2 + 6 + 1 === add5(3); // 8

Slide 232

Slide 232 text

Function Composition let multiply = curry((x, y) => x * y); let multiply2 = multiply(2); let multiply3 = multiply(3); let multiply6 = compose(multiply2, multiply3); 2 * 3 * 6 === multiply6(6); // 36 let add = curry((x, y) => x + y); let subtract = curry((y, x) => -y + x); let add5 = compose(add(6), add(1), subtract(2)); 3 - 2 + 6 + 1 === add5(3); // 8

Slide 233

Slide 233 text

Function Composition function compose(...fns) { return (...args) => { const result = fns.reduceRight((memo, fn) => { return [fn(...memo)]; }, args); return result[0]; }; } function compose(f, g) { return (...args) => f(g(...args)); }

Slide 234

Slide 234 text

Function Composition function compose(...fns) { return (...args) => { const result = fns.reduceRight((memo, fn) => { return [fn(...memo)]; }, args); return result[0]; }; } function compose(f, g) { return (...args) => f(g(...args)); }

Slide 235

Slide 235 text

Function Composition function compose(...fns) { return (...args) => { const result = fns.reduceRight((memo, fn) => { return [fn(...memo)]; }, args); return result[0]; }; } function compose(f, g) { return (...args) => f(g(...args)); }

Slide 236

Slide 236 text

Function Composition function compose(...fns) { return (...args) => { const result = fns.reduceRight((memo, fn) => { return [fn(...memo)]; }, args); return result[0]; }; } function compose(f, g) { return (...args) => f(g(...args)); }

Slide 237

Slide 237 text

Function Composition function compose(...fns) { return (...args) => { const result = fns.reduceRight((memo, fn) => { return [fn(...memo)]; }, args); return result[0]; }; } function compose(f, g) { return (...args) => f(g(...args)); }

Slide 238

Slide 238 text

Slide 239

Slide 239 text

But why Functional Programming?

Slide 240

Slide 240 text

Why FP • Concise, elegant solutions to problems • Modularity and composition • Eliminate data races with immutability • Unit tests are simpler — no checking for state changes

Slide 241

Slide 241 text

Extra Resources • Babel (babeljs.io) • Lodash (lodash.com) • Clojurescript (github.com/clojure/clojurescript) • Immutable.js (github.com/facebook/immutable-js) • React (facebook.github.io/react/)

Slide 242

Slide 242 text

Thanks! jfairbank @elpapapollo blog.jeremyfairbank.com Code samples (some ES5 too) github.com/jfairbank/functional-javascript