Upgrade to Pro — share decks privately, control downloads, hide ads and more …

First Steps into Functional Programming

First Steps into Functional Programming

In recent years you may have found yourself hearing more and more about this trendy topic of “functional programming", from a bunch of excited coders enthusiastically gushing about how it helps them write elegant, modular code that's easier to test, debug, and reason about. If you're like me, you may have started wondering:

- What is functional programming anyway, and why are people so excited about it?
- What does functional code look like? How is it different from imperative or OO code?
- What tools do I need to write functional programs? Do I have to learn Haskell? (spoiler alert: no!)

If you too have been asking yourself questions like these, please join me in this friendly, practical exploration of functional programming fundamentals.

Follow along with the workshop materials: https://github.com/vakila/functional-workshop

Given at:
- NgTalks 2018: https://ngtalks.io/workshops/first-steps-into-functional-programming
- GOTO Copenhagen 2018: https://gotocph.com/2018/workshops/124

Anjana Sofia Vakil

August 09, 2018
Tweet

More Decks by Anjana Sofia Vakil

Other Decks in Programming

Transcript

  1. First Steps into
    Functional Programming
    https://github.com/vakila/functional-workshop
    @AnjanaVakil

    View Slide

  2. Who am I?
    @AnjanaVakil

    View Slide

  3. The Recurse Center
    https://www.recurse.com/

    View Slide

  4. Who are you?
    Let's share:
    - Name
    - Home base
    - Programming background/technologies
    - Interest/experience in FP

    View Slide

  5. What is functional programming?

    View Slide

  6. What is functional programming?
    a buzz-wordy trend

    View Slide

  7. pure functor
    side effect
    monad
    monoid
    compose
    curry
    λ
    immutable
    stateless
    lazy
    referential transparency
    higher-order

    View Slide

  8. pure functor
    side effect
    monad
    monoid
    compose
    curry
    λ
    immutable
    stateless
    lazy
    referential transparency
    higher-order
    ???

    View Slide

  9. What is functional programming?
    a coding style
    supported by some languages

    View Slide

  10. Clojure
    Haskell
    JavaScript!
    Erlang
    Elm
    Scala
    F#
    OCaml

    View Slide

  11. What is functional programming?
    a programming paradigm
    (worldview, mindset)

    View Slide

  12. Imperative
    follow my commands
    do this, then that
    Object-Oriented
    keep state to yourself
    send/receive messages
    Declarative
    this is what I want
    I don't care how you do it
    Functional
    ???

    View Slide

  13. What is functional programming?
    one simple idea

    View Slide

  14. https://codewords.recurse.com/issues/one/an-introduction-to-functional-programming

    View Slide

  15. pure functions
    only input in
    only output out

    View Slide

  16. Not pure:
    let name = "Alonzo";
    function greet() {
    console.log("Hello, " + name + "!");
    }
    greet(); // Hello, Alonzo!
    name = "Alan";
    greet(); // Hello, Alan!

    View Slide

  17. Pure:
    function greet(name) {
    return "Hello, " + name + "!";
    }
    greet("Alonzo");
    // "Hello, Alonzo!"
    greet("Alan");
    // "Hello, Alan!"

    View Slide

  18. Why functional programming?

    View Slide

  19. Why functional programming?
    more predictable, safer

    View Slide

  20. Why functional programming?
    easier to test/debug

    View Slide

  21. Why functional programming?
    makes you look/feel smart
    is The Best™ paradigm

    View Slide

  22. Why functional JavaScript?

    View Slide

  23. Why functional JavaScript?
    object-oriented JS gets tricky
    (prototypes? this?!?)

    View Slide

  24. Why functional JavaScript?
    established community/tools

    View Slide

  25. OK, let’s do it!

    View Slide

  26. OK, let’s do it!
    ...how?

    View Slide

  27. Do everything with functions
    program === function(s)

    View Slide

  28. Imperative:
    let name = "Alonzo";
    let greeting = "Hi";
    console.log(greeting + ", " + name + "!");
    // Hi, Alonzo!
    greeting = "Howdy";
    console.log(greeting + ", " + name + "!");
    // Howdy, Alonzo!

    View Slide

  29. Functional:
    function greet(greeting, name) {
    return greeting + ", " + name + "!";
    }
    greet("Hi", "Alonzo");
    // "Hi, Alonzo!"
    greet("Howdy", "Alan");
    // "Howdy, Alan!"

    View Slide

  30. Avoid side effects
    do nothing but return output

    View Slide

  31. Side effects:
    let thesis = {name: "Church's", date: 1936};
    function renameThesis(newName) {
    conf.name = newName;
    console.log("Renamed!");
    }
    renameThesis("Church-Turing"); // Renamed!
    thesis; //{name: "Church-Turing", date: 1936}

    View Slide

  32. No side effects:
    const thesis = {name: "Church's", date: 1936};
    function renameThesis(oldThesis, newName) {
    return {name: newName, date: oldThesis.date}
    }
    const thesis2 = renameThesis(ct,"Church-Turing");
    thesis2; // {name: "Church's", date: 1936}
    thesis; // {name: "Church-Turing", date: 1936}

    View Slide

  33. Let’s do it!
    github.com/vakila/functional-workshop/
    tree/master/pure-functions

    View Slide

  34. Don’t iterate
    recurse

    View Slide

  35. Iteration:
    function sum (numbers) {
    let total = 0;
    for (i = 0; i < numbers.length; i++) {
    total += numbers[i];
    }
    return total;
    }
    sum([0,1,2,3,4]); // 10

    View Slide

  36. Recursion:
    function sum (numbers) {
    if (numbers.length === 1) {
    return numbers[0];
    } else {
    return numbers[0] + sum(numbers.slice(1));
    }
    }
    sum([0,1,2,3,4]); // 10

    View Slide

  37. The problem with recursion
    infinite repetition vs.
    finite resources

    View Slide

  38. The problem with recursion
    // recursiveInception.js
    'use strict';
    const recursiveInception = (n) => {
    if (n === 0) return "a dream";
    let dreams = recursiveInception(n-1);
    return dreams + " within a dream";
    }
    const depth = parseInt(process.argv[2]);
    console.log(recursiveInception(depth));
    $ node recursiveInception.js 30000
    /home/anjana/recursiveInception.js:4
    const recursiveInception = (n) => {
    ^
    RangeError: Maximum call stack size exceeded
    at recursiveInception (recursiveInception.js:4:28)
    at recursiveInception (recursiveInception.js:6:16)
    at recursiveInception (recursiveInception.js:6:16)
    at recursiveInception (recursiveInception.js:6:16)
    at recursiveInception (recursiveInception.js:6:16)
    at recursiveInception (recursiveInception.js:6:16)
    at recursiveInception (recursiveInception.js:6:16)
    at recursiveInception (recursiveInception.js:6:16)
    at recursiveInception (recursiveInception.js:6:16)
    at recursiveInception (recursiveInception.js:6:16)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

    From "Recursion, Iteration & JS: A love story"

    View Slide

  39. // tailRecursiveInception.js
    'use strict';
    const tailRecursiveInception = (n) => {
    const incept = (n, dreams) => {
    if (n === 0) return dreams;
    return incept(n-1, dreams+" within a dream");
    }
    return incept(n, "a dream");
    }
    const depth = parseInt(process.argv[2]);
    console.log(tailRecursiveInception(depth));
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    $ nvm use 6
    Now using node v6.12.3
    $ node --harmony_tailcalls
    tailRecursiveInception.js 30000
    a dream within a dream within a dream
    within a dream within a dream within a
    dream within a dream within a dream within a
    dream within a dream within a dream within a dream
    within a dream within a dream within a dream within a dream
    within a dream within a dream within a dream within a dream
    within a dream within a dream within a dream within a dream within a dream
    within a dream within a dream within a dream within a dream within a dream within a
    dream within a dream within a dream within a dream within a dream within a dream within a dream
    within a dream within a dream within a dream within a dream within a dream within a dream within a
    dream within a dream within a dream within a dream within a dream within a dream within a dream
    within a dream within a dream within a dream within a dream within a dream within a dream within a
    dream within a dream within a dream within a dream within a dream within a dream within a dream
    within a dream within a dream within a dream within a dream within a dream within a dream within a
    dream within a dream within a dream within a dream within a dream within a dream within a dream
    within a dream within a dream within a dream within a dream within a dream within a dream within a
    dream within a dream within a dream within a dream within a dream within a dream within a dream
    within a dream within a dream within a dream within a dream within a dream within a dream within a
    dream within a dream within a dream within a dream within a dream within a dream within a dream
    within a dream within a dream within a dream within a dream within a dream within a dream within a
    dream within a dream within a dream within a dream within a dream within a dream within a dream
    within a dream within a dream within a dream within a dream within a dream within a dream within a
    dream within a dream within a dream within a dream within a dream within a dream within a within a
    dream within a dream within a dream within …………………..
    Tail call optimization
    From "Recursion, Iteration & JS: A love story"

    View Slide

  40. Let’s do it!
    github.com/vakila/functional-workshop/
    tree/master/recursion

    View Slide

  41. Use higher-order functions
    functions with functions
    as inputs/outputs

    View Slide

  42. Don’t loop
    use map, reduce, filter

    View Slide

  43. Filter
    Figure adapted from
    http://www.datasciencecentral.com/forum/topics/what-is-map-reduce

    View Slide

  44. Let’s do it!
    github.com/vakila/functional-workshop/
    tree/master/higher-order

    View Slide

  45. More higher-order functions
    outputting functions
    that "remember" scope

    View Slide

  46. Closure:
    function makeAdjectifier(adjective) {
    return function (noun) {
    return adjective + " " + noun;
    };
    }
    const coolify = makeAdjectifier("cool");
    coolify("conference"); // "cool conference"
    coolify("drink"); // "cool drink"

    View Slide

  47. Currying:
    const curryGreet = (greeting) => {
    return (name) => {
    return greeting + ", " + name + "!";
    };
    };
    const greetEng = curryGreet("Hi");
    greetEng("Alonzo"); // "Hi, Alonzo!"
    const greetTex = curryGreet("Howdy");
    greetTex("Alonzo"); // "Howdy, Alonzo!"

    View Slide

  48. FP & OOP: BFFs?
    down the closure rabbit hole
    to "functional objects"

    View Slide

  49. thing.do(some,stuff)
    => behavior
    From "Oops! OOP's not what I thought"

    View Slide

  50. to: thing
    subject: pretty please? :D
    message: "do", some, stuff
    From "Oops! OOP's not what I thought"

    View Slide

  51. recipient message
    thing.do(some,stuff)
    From "Oops! OOP's not what I thought"

    View Slide

  52. recipient message
    thing.do(some,stuff)
    method name arguments
    From "Oops! OOP's not what I thought"

    View Slide

  53. recipient message
    thing('do',some,stuff)
    method name arguments
    From "Oops! OOP's not what I thought"

    View Slide

  54. recipient message
    thing('do')(some)(stuff)
    method name arguments
    From "Oops! OOP's not what I thought"

    View Slide

  55. Smalltalk (OOP)
    class True
    ifTrue: a ifFalse: b
    ^ a value
    class False
    ifTrue: a ifFalse: b
    ^ b value
    Lambda calculus (FP)
    TRUE := λx.λy.x
    FALSE := λx.λy.y
    See also: gist.github.com/vakila -> LilLambda.ipynb

    View Slide

  56. Let’s do it!
    github.com/vakila/functional-workshop/
    tree/master/closure

    View Slide

  57. It's functions all the way down
    program === function(s)

    View Slide

  58. Flow data through functions
    outputs become inputs become outputs

    View Slide

  59. Composing functions:
    var ender = (ending) => (input) => input + ending;
    var adore = ender(" rocks");
    var announce = ender(", y'all");
    var exclaim = ender("!");
    var hypeUp = (x) => exclaim(announce(adore(x)));
    hypeUp("JS"); // "JS rocks, y'all!"
    hypeUp("FP"); // "FP rocks, y'all!"

    View Slide

  60. Helpers for composition/pipelining:
    const r = require("ramda");
    const rtlHype = r.compose(adore,announce,exclaim);
    rtlHype("FP"); // "FP!, y'all rocks"
    const ltrHype = r.pipe(adore, announce, exclaim);
    ltrHype("FP"); // "FP rocks, y'all!"

    View Slide

  61. Let’s do it!
    github.com/vakila/functional-workshop/
    tree/master/composition

    View Slide

  62. Avoid mutability
    don't change in-place;
    instead, replace

    View Slide

  63. Mutation (dangerous!):
    let cities = ["Delhi", "Bombay", "Bangalore"];
    cities[1] = "Mumbai";
    cities;
    // ["Delhi", "Bombay", "Bangalore"]

    View Slide

  64. No mutation (safer!):
    const cities = ["Delhi", "Bombay", "Bangalore"];
    const newCities = cities.map((city) => {
    if (city === "Bombay") { return "Mumbai"; }
    else { return city; }
    });
    newCities;//["Delhi", "Mumbai", "Bangalore"]
    cities; //["Delhi", "Bombay", "Bangalore"]

    View Slide

  65. 0 1 2 3 4 5 6 7
    foo
    Mutable data

    View Slide

  66. 8 1 2 3 4 5 6 7
    foo
    Mutable data

    View Slide

  67. 0 1 2 3 4 5 6 7
    foo
    Immutable data

    View Slide

  68. 0 1 2 3 4 5 6 7
    foo
    8 1 2 3 4 5 6 7
    too
    Immutable data

    View Slide

  69. 0 1 2 3 4 5 6 7
    foo
    8 1 2 3 4 5 6 7
    too
    Immutable data (inefficient)

    View Slide

  70. Use persistent data structures
    for efficient immutability
    See also: "Immutable Data Structures for Functional JS"

    View Slide

  71. 0 1 2 3 4 5 6 7
    foo
    Immutable data (efficient)

    View Slide

  72. 0 1 2 3 4 5 6 7
    foo
    Immutable data (efficient)

    View Slide

  73. 0 1 2 3
    foo
    4 5 6 7
    1
    8
    too
    Immutable data (efficient)

    View Slide

  74. 0 1 2 3
    foo
    4 5 6 7
    1
    8
    too
    Persistent (immutable) data structures
    structural
    sharing

    View Slide

  75. Mori
    https://swannodette.github.io/mori
    var f = mori.vector(1,2);
    var t = mori.conj(f, 3);
    ● ClojureScript port
    ● Functional API
    ● Fast
    Immutable.js
    https://facebook.github.io/immutable-js
    var f = Immutable.List.of(1,2);
    var t = f.push(3);
    ● JS through & through
    ● Public methods
    ● A bit smaller than Mori
    Persistent data structures

    View Slide

  76. Let’s do it!
    github.com/vakila/functional-workshop/
    tree/master/immutability

    View Slide

  77. Recap
    - What key ideas will help you "think functionally"?
    - When is FP the right fit?
    - What concepts are you eager to look into next?

    View Slide

  78. Further reading:
    github.com/vakila/functional-workshop#references--further-reading
    Functional libraries/languages to try:
    github.com/vakila/functional-workshop#libraries--languages-to-try

    View Slide

  79. Thanks for joining!
    I’m @AnjanaVakil
    Huge thanks to:
    Mary Rose Cook, Sal Becker,
    Khalid Ali & The Recurse Center

    View Slide