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

Stack Wars - Functional Programming Strikes back!

Stack Wars - Functional Programming Strikes back!

As our codebase grows, so its complexity does. Code it’s becoming harder to read, test, debug, maintain… such a mess! Let’s go back to the cool ’80s and start a journey to discover a different way to approach software development: Functional Programming. We’ll see how FP can actually save hours of debugging and improve our productivity while writing a complex frontend JavaScript application or a huge backend distributed system in any programming language. You’ll never write an impure function again!

Avatar for Michele Riva

Michele Riva

October 24, 2019

Other Decks in Programming

Transcript

  1. LAMBDA FUNCTIONS LAMBDA FUNCTIONS I BET YOU'RE ALREADY USING THEM

    λx.x+x lambda x: x + x Lambda Calculus Python
  2. LAMBDA FUNCTIONS LAMBDA FUNCTIONS I BET YOU'RE ALREADY USING THEM

    λx.x+x (x) => x + x; Lambda Calculus JavaScript
  3. BOOLEANS? BOOLEANS? WHO NEEDS BOOLEANS? λx.λy.x ;true λx.λy.y ;false const

    TRUE = x => y => x; const FALSE = x => y => y; Lambda Calculus JavaScript
  4. CONTROL STRUCTURES? CONTROL STRUCTURES? WHO NEEDS THEM? λz.(λx.(λy.zxy)) ;if/then/else const

    IF = COND => THEN => ELSE => COND(THEN)(ELSE); Lambda Calculus JavaScript
  5. let approved = []; for (let i = 0; i

    < approved.length; i++) { if (users[i].score >= 7) { approved.push(approved); } } 1 2 3 4 5 6 7 const approved = users.filter((user) => user.score >= 7); 1 Mutates a value Does not mutate a value PURITY MEANS PURITY MEANS IMMUTABILITY
  6. let user = { name: "John" }; function addLastName(lastName) {

    user[lastName] = "Doe"; }; 1 2 3 4 5 const addLastName = (obj, lastName) => ({ ...obj, lastName }); 1 Causes a side effect Does not cause a side effect PURITY MEANS PURITY MEANS NO SIDE EFFECTS
  7. const fact = n => n === 0 ? 1

    : n * fact(n - 1); console.log(`Fact of 5: ${fact(5)}`); 1 2 3 Uses loops Uses recursion let result = 1; for (let i = 2; i <= 5; i++) { result *= i; } console.log('Fact of 5: ', result); 1 2 3 4 5 6 7 PURITY MEANS PURITY MEANS NO LOOPS
  8. import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; public class Main {

    public static void main(String[] args) { List<String> numbers = Arrays.asList("1", "2", "3", "4", "5", "6"); List<Integer> even = numbers.stream() .map(s -> Integer.valueOf(s)) .filter(number -> number % 2 == 0) .collect(Collectors.toList()); System.out.println("Even numbers in list: " + even); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 PURITY MEANS PURITY MEANS NO LOOPS
  9. import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; public class Main {

    public static void main(String[] args) { List<String> numbers = Arrays.asList("1", "2", "3", "4", "5", "6"); Integer sum = numbers.stream() .map(s -> Integer.valueOf(s)) .reduce(0, (x, y) -> x + y); System.out.println("Sum of list is: " + sum); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 PURITY MEANS PURITY MEANS NO LOOPS
  10. function addX(num) { const x = 10; return num +

    x; } 1 2 3 4 Result may change over time due to mutability let x = 10; function addX(num) { return num + x; } 1 2 3 4 5 PURITY MEANS PURITY MEANS REFERENTIAL TRANSPARENCY Always produces the same result when the same arguments are given
  11. function statelessCounter(iterations) { ... return statelessCounter(iteration + 1); } 1

    2 3 4 Updates the state on each iteration let myCounter = 0; while (true) { ... myCounter++; }; 1 2 3 4 5 6 PURITY MEANS PURITY MEANS NO STATE Creates a new "state" with every recursive function call
  12. "greet" is a function that returns a list of chars

    greet :: [Char] greet = "Hello World!" 1 2 PURITY MEANS PURITY MEANS NO ASSIGNMENT STATEMENTS
  13. Logging a string to the I/O means mutating the I/O

    stream main :: IO() main = putStrLn "Hello World!" 1 2 No randomness import System.Random import Control.Monad (replicateM) main = replicateM 10 (randomIO :: IO Float) >>= print 1 2 3 4 PURITY MEANS PURITY MEANS NO SIDE EFFECTS AT ALL
  14. QuickSort algorithm in C++ template <typename T> void qsort (T

    *result, T *list, int n) { if (n == 0) return; T *smallerList, *largerList; smallerList = new T[n]; largerList = new T[n]; T pivot = list[0]; int numSmaller=0, numLarger=0; for (int i = 1; i < n; i++) if (list[i] < pivot) smallerList[numSmaller++] = list[i]; else largerList[numLarger++] = list[i]; qsort(smallerList,smallerList,numSmaller); qsort(largerList,largerList,numLarger); int pos = 0; for ( int i = 0; i < numSmaller; i++) result[pos++] = smallerList[i]; result[pos++] = pivot; for ( int i = 0; i < numLarger; i++) result[pos++] = largerList[i]; delete [] smallerList; delete [] largerList; }; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 WHY PURITY MATTERS WHY PURITY MATTERS PURE FUNCTIONS ARE EASIER TO REASON ABOUT
  15. QuickSort algorithm in Haskell qsort :: Ord a => [a]

    -> [a] qsort [] = [] qsort (x:xs) = qsort smaller ++ [x] ++ qsort bigger where smaller = filter (< x) xs bigger = filter (>= x) xs 1 2 3 4 5 6 WHY PURITY MATTERS WHY PURITY MATTERS PURE FUNCTIONS ARE EASIER TO REASON ABOUT
  16. qsort :: Ord a => [a] -> [a] qsort []

    = [] qsort (x:xs) = qsort smaller ++ [x] ++ qsort bigger where smaller = filter (< x) xs bigger = filter (>= x) xs 1 2 3 4 5 6 WHY PURITY MATTERS WHY PURITY MATTERS PURE FUNCTIONS ARE EASIER TO REASON ABOUT
  17. Testing functions with side effects function callPizzeria(phone: number): void {

    ... }; function waitForPizza(patience: any): void { ... }; 1 2 WHY PURITY MATTERS WHY PURITY MATTERS TESTING IS EASIER test("Testing a method that has an hidden state and side-effects", () => { callPizzeria(phone); waitForPizza(patience); drinkBeer(can); let pizza = getPizzaFromPizzaboy(cash); expect(pizza).toBe(expectedPizza); }); 1 2 3 4 5 6 7 8 9 10
  18. Testing functions without side effects test("Testing a pure function is

    easier", () => { const result = compose( addOne, multiplyBy5, subtract5 )(10); expect(result).tobe(26); }); 1 2 3 4 5 6 7 WHY PURITY MATTERS WHY PURITY MATTERS TESTING IS EASIER
  19. Quicksort algorithm in Elixir def quicksort([]), do: [] def quicksort([pivot|t])

    do quicksort(for x <- t, x < pivot, do: x) ++ [pivot] ++ quicksort(for x <- t, x >= pivot, do: x) end 1 2 3 4 5 6 WHY PURITY MATTERS WHY PURITY MATTERS DEBUGGING IS EASIER
  20. Quicksort algorithm in Erlang qsort([]) -> []; qsort([Pivot|Rest]) -> qsort([

    X || X <- Rest, X < Pivot]) ++ [Pivot] ++ qsort([ Y || Y <- Rest, Y >= Pivot]). 1 2 3 4 5 WHY PURITY MATTERS WHY PURITY MATTERS DEBUGGING IS EASIER
  21. Quicksort algorithm in OCaml let rec quicksort = function |

    [] -> [] | x::xs -> let (smaller,larger) = List.partition (fun y -> y < x) xs in (quicksort smaller) @ (x :: (quicksort larger)) 1 2 3 4 5 6 WHY PURITY MATTERS WHY PURITY MATTERS DEBUGGING IS EASIER
  22. Quicksort algorithm in F# let rec qsort = function hd

    :: tl -> let less, greater = List.partition ((>=) hd) tl List.concat [qsort less; [hd]; qsort greater] | _ -> [] 1 2 3 4 5 WHY PURITY MATTERS WHY PURITY MATTERS DEBUGGING IS EASIER
  23. Quicksort algorithm in Clojure (defn quicksort [seq] (if (emtpy? seq)

    [] (let [x (first seq) xs (rest seq)] (concat (quicksort (filter (fn [v] (<= v x)) xs)) [x] (quicksort (filter (fn [v] (> v x)) xs)))))) 1 2 3 4 5 6 7 WHY PURITY MATTERS WHY PURITY MATTERS DEBUGGING IS EASIER
  24. Quicksort algorithm in Scala def qsort: List[Int] => List[Int] =

    { case Nil => Nil case pivot :: tail => val (smaller, rest) = tail.partition(_ < pivot) qsort(smaller) ::: pivot :: qsort(rest) } 1 2 3 4 5 6 WHY PURITY MATTERS WHY PURITY MATTERS DEBUGGING IS EASIER
  25. Integer sum = numbers.parallelStream() import java.util.Arrays; 1 import java.util.List; 2

    import java.util.stream.Collectors; 3 4 public class Main { 5 6 public static void main(String[] args) { 7 8 List<String> numbers = Arrays.asList("1", "2", "3", "4", "5", "6"); 9 10 11 .map(s -> Integer.valueOf(s)) 12 .reduce(0, (x, y) -> x + y); 13 14 System.out.println("Sum of list is: " + sum); 15 } 16 17 } 18 PURITY MEANS PURITY MEANS OUT-OF-THE BOX CONCURRENCY
  26. PURE FUNCTIONS ARE PURE FUNCTIONS ARE DETERMINISTIC f (x) ->

    x + x g (y) -> Y * y h (z) -> z + 2 1 2 3 4 5
  27. PURE FUNCTIONS ARE PURE FUNCTIONS ARE COMPOSABLE f (x) ->

    x + x g (y) -> Y * y h (z) -> z + 2 k (x) -> f(g(h(x))) 1 2 3 4 5 6 7
  28. PURE FUNCTIONS ARE PURE FUNCTIONS ARE DECLARATIVE double (x) ->

    x + x pow (y) -> Y * y addTwo (z) -> z + 2 makeMath (x) -> double(pow(addTwo(x))) 1 2 3 4 5 6 7
  29. PURE FUNCTIONS ARE PURE FUNCTIONS ARE DECLARATIVE double (x) ->

    x + x pow (y) -> Y * y addTwo (z) -> z + 2 makeMath (x) -> { result = 0 result = double(x) result = pow(result) result = addTwo(result) return result } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
  30. PURE FUNCTIONS ARE PURE FUNCTIONS ARE DECLARATIVE If we list

    all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23. Find the sum of all the multiples of 3 or 5 below 1000. Project Euler, Problem #1 - https://projecteuler.net/problem=1
  31. PURE FUNCTIONS ARE PURE FUNCTIONS ARE DECLARATIVE public class Main

    { public static void main(String[] args) { int i, sum = 0; for ( i = 3; i < 1000; i++) { if (i % 3 == 0 || i % 5 == 0 ) { sum += i; } } System.out.print(sum); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
  32. PURE FUNCTIONS ARE PURE FUNCTIONS ARE DECLARATIVE import Data.List (union)

    solution :: Int solution = sum $ [3,6..limit] `union` [5,10..limit] where limit = 999 main :: IO() main = print $ solution 1 2 3 4 5 6 7 8
  33. PURE FUNCTIONS ARE PURE FUNCTIONS ARE DECLARATIVE def solution(): return

    sum([i for i in range(1, 1000) if i % 3 == 0 or i % 5 == 0]) 1 2 3
  34. PURE FUNCTIONS ARE PURE FUNCTIONS ARE DECLARATIVE const solution =

    [...Array(1000)] .map((_, i) => i) .filter(x => x % 3 === 0 || x % 5 === 0) .reduce((sum, x) => sum + x, 0); 1 2 3 4
  35. PURE FUNCTIONS ARE PURE FUNCTIONS ARE DECLARATIVE const sum =

    (x, y) => x + y; const isModZero = (x, y) => x % y === 0; const or = (x, y) => (x || y); const createArray = (length) => [...Array(length)].map((_, i) => i); const solution = (limit) => ( createArray(limit) .filter(x => or(isModZero(x, 5), isModZero(x, 3))) .reduce(sum, 0) ); const result = solution(1000); 1 2 3 4 5 6 7 8 9 10 11 12
  36. Ruby Java JavaScript .NET I want to write rock solid

    frontend I want to start from scratch Clojure Scala ReasonML F# Elm PureScript Haskell Elixir
  37. So should I get rid of my existing OOP/imperative code

    and refactor everything in a functional language?
  38. So should I get rid of my existing OOP/imperative code

    and refactor everything in a functional language?
  39. "Don't be a functional programmer. Dont' be an object programmer.

    Be a better programmer." Brian Goetz, Java Language Architect at Oracle
  40. LET'S KEEP IN TOUCH LET'S KEEP IN TOUCH MICHELE RIVA

    MICHELE RIVA Software Engineer at Openmind Founder of JSMonday.dev @MicheleRiva @MicheleRivaCode www.micheleriva.it [email protected]