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

654527a5cff1756177ef0b1bb0af7aa3?s=128

Anjana Sofia Vakil

August 09, 2018
Tweet

Transcript

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

  2. Who am I? @AnjanaVakil

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

  4. Who are you? Let's share: - Name - Home base

    - Programming background/technologies - Interest/experience in FP
  5. What is functional programming?

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

  7. pure functor side effect monad monoid compose curry λ immutable

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

    stateless lazy referential transparency higher-order ???
  9. What is functional programming? a coding style supported by some

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

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

  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 ???
  13. What is functional programming? one simple idea

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

  15. pure functions only input in only output out

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

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

    "!"; } greet("Alonzo"); // "Hello, Alonzo!" greet("Alan"); // "Hello, Alan!"
  18. Why functional programming?

  19. Why functional programming? more predictable, safer

  20. Why functional programming? easier to test/debug

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

    paradigm
  22. Why functional JavaScript?

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

  24. Why functional JavaScript? established community/tools

  25. OK, let’s do it!

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

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

  28. Imperative: let name = "Alonzo"; let greeting = "Hi"; console.log(greeting

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

    + name + "!"; } greet("Hi", "Alonzo"); // "Hi, Alonzo!" greet("Howdy", "Alan"); // "Howdy, Alan!"
  30. Avoid side effects do nothing but return output

  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}
  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}
  33. Let’s do it! github.com/vakila/functional-workshop/ tree/master/pure-functions

  34. Don’t iterate recurse

  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
  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
  37. The problem with recursion infinite repetition vs. finite resources

  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"
  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"
  40. Let’s do it! github.com/vakila/functional-workshop/ tree/master/recursion

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

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

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

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

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

  46. Closure: function makeAdjectifier(adjective) { return function (noun) { return adjective

    + " " + noun; }; } const coolify = makeAdjectifier("cool"); coolify("conference"); // "cool conference" coolify("drink"); // "cool drink"
  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!"
  48. FP & OOP: BFFs? down the closure rabbit hole to

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

  50. to: thing subject: pretty please? :D message: "do", some, stuff

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

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

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

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

    what I thought"
  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
  56. Let’s do it! github.com/vakila/functional-workshop/ tree/master/closure

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

  58. Flow data through functions outputs become inputs become outputs

  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!"
  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!"
  61. Let’s do it! github.com/vakila/functional-workshop/ tree/master/composition

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

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

    "Mumbai"; cities; // ["Delhi", "Bombay", "Bangalore"]
  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"]
  65. 0 1 2 3 4 5 6 7 foo Mutable

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

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

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

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

    1 2 3 4 5 6 7 too Immutable data (inefficient)
  70. Use persistent data structures for efficient immutability See also: "Immutable

    Data Structures for Functional JS"
  71. 0 1 2 3 4 5 6 7 foo Immutable

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

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

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

    8 too Persistent (immutable) data structures structural sharing
  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
  76. Let’s do it! github.com/vakila/functional-workshop/ tree/master/immutability

  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?
  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

  79. Thanks for joining! I’m @AnjanaVakil Huge thanks to: Mary Rose

    Cook, Sal Becker, Khalid Ali & The Recurse Center