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. Who are you? Let's share: - Name - Home base

    - Programming background/technologies - Interest/experience in FP
  2. pure functor side effect monad monoid compose curry λ immutable

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

    stateless lazy referential transparency higher-order ???
  4. 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 ???
  5. Not pure: let name = "Alonzo"; function greet() { console.log("Hello,

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

    "!"; } greet("Alonzo"); // "Hello, Alonzo!" greet("Alan"); // "Hello, Alan!"
  7. Imperative: let name = "Alonzo"; let greeting = "Hi"; console.log(greeting

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

    + name + "!"; } greet("Hi", "Alonzo"); // "Hi, Alonzo!" greet("Howdy", "Alan"); // "Howdy, Alan!"
  9. 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}
  10. 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}
  11. 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
  12. 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
  13. 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"
  14. // 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"
  15. Closure: function makeAdjectifier(adjective) { return function (noun) { return adjective

    + " " + noun; }; } const coolify = makeAdjectifier("cool"); coolify("conference"); // "cool conference" coolify("drink"); // "cool drink"
  16. 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!"
  17. 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
  18. 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!"
  19. 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!"
  20. Mutation (dangerous!): let cities = ["Delhi", "Bombay", "Bangalore"]; cities[1] =

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

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

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

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

    8 too Persistent (immutable) data structures structural sharing
  26. 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
  27. Recap - What key ideas will help you "think functionally"?

    - When is FP the right fit? - What concepts are you eager to look into next?
  28. Thanks for joining! I’m @AnjanaVakil Huge thanks to: Mary Rose

    Cook, Sal Becker, Khalid Ali & The Recurse Center