Slide 1

Slide 1 text

Functional JavaScript for Beginners

Slide 2

Slide 2 text

Hi, I'm Steve.

Slide 3

Slide 3 text

@stevekinney

Slide 4

Slide 4 text

http://turing.io

Slide 5

Slide 5 text

@dinosaur_js June 24, 2016 in Denver. You can use the code moonconf for $60 off.

Slide 6

Slide 6 text

Today we'll cover the following topics

Slide 7

Slide 7 text

· What functional programming even is · Functions as first-class objects · Pure versus impure functions · Partial application · Currying

Slide 8

Slide 8 text

What is functional programming?

Slide 9

Slide 9 text

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. — Wikipedia

Slide 10

Slide 10 text

What is a pure function?

Slide 11

Slide 11 text

A pure function is one that takes arguments and returns a value without having any side effects.

Slide 12

Slide 12 text

const add = function (a, b) { return a + b; }; This is a pure function.

Slide 13

Slide 13 text

const randomNumbers = []; const addARandomNumber = function () { randomNumbers.push(Math.random()); }; This is an impure function.

Slide 14

Slide 14 text

It doesn't take any inputs. It doesn't return any value. It has a side effect.

Slide 15

Slide 15 text

Gross.

Slide 16

Slide 16 text

Is JavaScript a functional programming language?

Slide 17

Slide 17 text

It depends.

Slide 18

Slide 18 text

JavaScript is what we call a multi-paradigm language.

Slide 19

Slide 19 text

We can write JavaScript in all sorts of styles.

Slide 20

Slide 20 text

Imperative Object-oriented Prototypal Functional

Slide 21

Slide 21 text

Let's take a quick look at some imperative code.

Slide 22

Slide 22 text

let result; function capitalizeWord(input) { var counter; var inputArray = input.split(" "); var transformed = ""; result = []; for (counter = 0; counter < inputArray.length; counter++) { transformed = [ inputArray[counter].charAt(0).toUpperCase(), inputArray[counter].substring(1) ].join(""); result.push(transformed); } }; (Don't even try to grok this.)

Slide 23

Slide 23 text

This code works, but it has some problems.

Slide 24

Slide 24 text

It modifies a global variable (e.g. result).

Slide 25

Slide 25 text

It combines the process of splitting the words up and transforming them.

Slide 26

Slide 26 text

It's not DRY.

Slide 27

Slide 27 text

Don't Repeat Yourself (Acronyms are fun, right?)

Slide 28

Slide 28 text

We can image a world where we might want to do a bit more.

Slide 29

Slide 29 text

SCREAMING CASE all lower case CrAzY CaSe uʍop ǝpᴉsdn

Slide 30

Slide 30 text

The Key to Functional Programming

Slide 31

Slide 31 text

Break your code into super small and reusable functions.

Slide 32

Slide 32 text

const capitalize = function (input) { return [input.charAt(0).toUpperCase(), input.substring(1)].join(''); } const processWords = function (fn, string) { return str.split(" ").map(fn).join(" "); } processWords(capitalize, 'hello world');

Slide 33

Slide 33 text

map and reduce

Slide 34

Slide 34 text

const veryImportantNumbers = [1, 4, 15]; Let's say we have some very important numbers and we want to double them.

Slide 35

Slide 35 text

We could totally do it in an imperative style.

Slide 36

Slide 36 text

const veryImportantNumbers = [1, 4, 15]; const doubledNumbers = []; for (let i; i < veryImportantNumbers.length; i++) { const number = veryImportantNumbers[i]; doubledNumbers.push(number); }

Slide 37

Slide 37 text

Ugh.

Slide 38

Slide 38 text

What if we tried this again with some functional programming?

Slide 39

Slide 39 text

map · takes an array of things, · runs each thing through a (hopefully) pure function, · returns a new array of things

Slide 40

Slide 40 text

const veryImportantNumbers = [1, 4, 15]; const double = (n) => n * 2; const doubledNumbers = veryImportantNumbers.map(double);

Slide 41

Slide 41 text

const veryImportantNumbers = [1, 4, 15]; const double = function (n) { return n * 2 }; const doubledNumbers = veryImportantNumbers.map(double);

Slide 42

Slide 42 text

const veryImportantNumbers = [1, 4, 15]; const double = (n) => n * 2; const doubledNumbers = veryImportantNumbers.map(double);

Slide 43

Slide 43 text

const veryImportantNumbers = [1, 4, 15]; const double = (n) => n * 2; const square = (n) => n * n; const halve = (n) => n / 2; const addOne = (n) => n + 1; const doubledNumbers = veryImportantNumbers.map(double); const squaredNumbers = veryImportantNumbers.map(square); const halvedNumbers = veryImportantNumbers.map(halve); const numbersPlusOne = veryImportantNumbers.map(addOne);

Slide 44

Slide 44 text

In JavaScript, the syntax is a little squirrely because it's a method on Array objects.

Slide 45

Slide 45 text

_.map(verImportantNumbers, double); Lodash does this a bit better.

Slide 46

Slide 46 text

_.map(verImportantNumbers, double); processWords(capitalize, 'hell world'); This is not unlike our first example.

Slide 47

Slide 47 text

reduce · Takes an array of things · Set ups an "accumulator" · Passes each one into a (hopefully) pure function · Returns the accumulator

Slide 48

Slide 48 text

const veryImportantNumbers = [1, 4, 15]; let sum = 0; for (let i; i < veryImportantNumbers.length; i++) { sum += veryImportantNumbers[i];; }

Slide 49

Slide 49 text

const veryImportantNumbers = [1, 4, 15]; const add = (a, b) => a + b; const sum = veryImportantNumbers.reduce(add);

Slide 50

Slide 50 text

const veryImportantNumbers = [1, 4, 15]; const add = (a, b) => a + b; const multiply = (a, b) => a * b; const sum = veryImportantNumbers.reduce(add); const factorial = veryImportantNumbers.reduce(multiply);

Slide 51

Slide 51 text

We say that functions are "composable."

Slide 52

Slide 52 text

const veryImportantNumbers = [1, 4, 15]; let doubleSum = 0; for (let i; i < veryImportantNumbers.length; i++) { doubleSum += veryImportantNumbers[i] * 2; } This whole process is "tightly coupled."

Slide 53

Slide 53 text

const veryImportantNumbers = [1, 4, 15]; const double = (n) => n * 2; const add = (a, b) => a + b; const doubleSum = veryImportantNumbers.map(double).reduce(add);

Slide 54

Slide 54 text

const veryImportantNumbers = [1, 4, 15]; const map = _.map; const reduce = _.reduce; const double = (n) => n * 2; const add = (a, b) => a + b; const doubleSum = double(reduce(veryImportantNumbers, add));

Slide 55

Slide 55 text

JavaScript infamously has a C-inspired syntax.

Slide 56

Slide 56 text

double(reduce(veryImportantNumbers, add)); As a result, when we write functional style code, we have to read it from the inside out.

Slide 57

Slide 57 text

reduce(veryImportantNumbers, add) |> double In some other languages, there is syntax to read it in the correct order.

Slide 58

Slide 58 text

There is a proposal to bring this to JavaScript in the future.

Slide 59

Slide 59 text

We can also solve this problem using Lodash's chain feature. const veryImportantNumbers = [1, 4, 15]; const { map, reduce, chain } = _; const double = (n) => n * 2; const add = (a, b) => a + b; chain(veryImportantNumbers).map(double).reduce(add).value(); But, it only really works with Lodash's functions.

Slide 60

Slide 60 text

Unless you engage in some tomfoolery. const veryImportantNumbers = [1, 4, 15]; const { map, reduce, chain } = _; const double = (n) => n * 2; const add = (a, b) => a + b; _.mixin({ double }); chain(veryImportantNumbers).reduce(add).double().value();

Slide 61

Slide 61 text

Partial Application

Slide 62

Slide 62 text

Partial application is a technique where we provide some of the arguments to a function now and the rest later.

Slide 63

Slide 63 text

This is useful because it allows us to use functions as templates for other functions.

Slide 64

Slide 64 text

In JavaScript, we can do this using Function.prototype.bind.

Slide 65

Slide 65 text

const add = (a, b) => a + b; const addOne = add.bind(this, 1); const subtractFive = add.bind(this, -5); addOne(5); // returns 6 subtractFive(12); // returns 7

Slide 66

Slide 66 text

Confusingly, bind() takes a context as the first argument. It then uses the second argument to partially apply the first argument to the function you're calling it on.

Slide 67

Slide 67 text

Everyone got that?

Slide 68

Slide 68 text

(Don't shoot the messenger.)

Slide 69

Slide 69 text

const add = (a, b) => a + b; const addOne = add.bind(this, 1); const addOne = add.bind(null, 1); const addOne = add.bind('sandwich', 1); If you're not using this in the function, then that first argument can be anything.

Slide 70

Slide 70 text

const superAdd = (a, b, c, d) => a + b + c + d; const oneArgumentApplied = superAdd.bind(this, 1); // ! — waiting on b, c, and d. const twoArgumentsApplied = superAdd.bind(this, 1, 2); // ! — waiting on c and d. const threeArgumentsApplied = superAdd.bind(this, 1, 2, 3); // ! — waiting on d. const fourArgumentsApplied = superAdd.bind(this, 1, 2, 3, 4); // ! — ready to call with no additional arguments.

Slide 71

Slide 71 text

Alternatively…

Slide 72

Slide 72 text

const superAdd = (a, b, c, d) => a + b + c + d; const oneArgumentApplied = (b, c, d) => superAdd(1, b, c, d); const twoArgumentsApplied = (c, d) => superAdd(1, 2, c, d); const threeArgumentsApplied = (d) => superAdd(1, 2, 3, d); const fourArgumentsApplied = () => superAdd(1, 2, 3, 4);

Slide 73

Slide 73 text

const add = (a, b) => a + b; const addOne = (b) => add(1, b); const subtractFive = (b) => add(-5, b); addOne(5); // returns 6 subtractFive(12); // returns 7

Slide 74

Slide 74 text

const superAdd = (a, b, c, d) => a + b + c + d; const oneArgumentApplied = superAdd.bind(this, 1); const twoArgumentsApplied = oneArgumentApplied.bind(this, 2); const threeArgumentsApplied = twoArgumentsApplied.bind(this, 3); const fourArgumentsApplied = threeArgumentsApplied.bind(this, 4);

Slide 75

Slide 75 text

Currying

Slide 76

Slide 76 text

Haskell Curry, 1900 – 1982

Slide 77

Slide 77 text

const addThreeNumbers = (a, b, c) => a + b + c; addThreeNumbers(1, 2, 3); // returns 6 This is a non-curried function.

Slide 78

Slide 78 text

const curriedAdd = (a) => { return (b) => { return (c) => { return a + b + c; } } }; curriedAdd(1)(2)(3); // returns 6

Slide 79

Slide 79 text

Or, more tersely: const curriedAdd = (a) => (b) => (c) => a + b + c;

Slide 80

Slide 80 text

const firstArgumentApplied = curriedAdd(1); // returns a function const secondArgumentApplied = firstArgumentApplied(2); // returns a function const thirdArgumentApplied = secondArgumentApplied(3); // returns 6

Slide 81

Slide 81 text

Why would I ever do this to myself?

Slide 82

Slide 82 text

Let's say it was out job to make a bunch of functions that took some text and wrapped them in HTML tags.

Slide 83

Slide 83 text

const wrapInParagraphTags = (body) => '

' + body + '

'; const wrapInHeaderTags = (body) => '

' + body + '

'; const wrapInListItemTags = (body) => '
  • ' + body + '
  • '; (And like a hundred other functions.)

    Slide 84

    Slide 84 text

    One day, the boss walks in and says "HTML is dead!"

    Slide 85

    Slide 85 text

    Now, you have to change all of those functions.

    Slide 86

    Slide 86 text

    But, you wouldn't have had to if you use currying.

    Slide 87

    Slide 87 text

    const createWrapper = (tag) => { return (body) => { return `<${tag}>${body}` }; } const wrapInParagraphTags = createWrapper('p'); const p = wrapInParagraphTags('Currying FTW!'); // ! returns `

    Currying FTW!

    ` const h2 = createWrapper('h2')('Hello world'); // ! returns `

    Hello world

    `

    Slide 88

    Slide 88 text

    Now, we'd only have to quickly change createWrapper and we're good to go.

    Slide 89

    Slide 89 text

    const createWrapper = (tag) => (body) => `<${tag}>${body}`;

    Slide 90

    Slide 90 text

    We could also use partial application.

    Slide 91

    Slide 91 text

    const wrapInTags = (tag, body) => `<${tag}>${body}`; const wrapInParagraphTags = wrapInTags.bind(null, 'p'); const p = wrapInParagraphTags('Partial application FTW!'); const h2 = wrapInTags('h2', 'Hello world');

    Slide 92

    Slide 92 text

    TL;DR: Functional programming allows us to write super flexible composable code. It helps use keep our code DRY.

    Slide 93

    Slide 93 text

    Where do I go from here?

    Slide 94

    Slide 94 text

    Learning Nodeschool.io (http://bit.ly/fjs-ns)

    Slide 95

    Slide 95 text

    Books Functional JavaScript by Michael Fogus (http:// amzn.to/1U37sDu) Functional Programming in JavaScript by Luis Atencio (http://amzn.to/1U37DOX)

    Slide 96

    Slide 96 text

    Thank you! · @stevekinney · @dinosaur_js · http://turing.io