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

Functional Programming for "Dummies"

scato
July 05, 2017

Functional Programming for "Dummies"

Should have been called: An impractical introduction to Haskell for experienced PHP developers.

scato

July 05, 2017
Tweet

More Decks by scato

Other Decks in Technology

Transcript

  1. Functional Programming
    for Dummies*
    *) people without a degree in Computer Science

    View full-size slide

  2. Functional
    Programming
    is...

    View full-size slide

  3. “Functional” Programming
    function set_id($record, $id)
    {
    $record['id'] = $id;
    }

    View full-size slide

  4. 1. Properties of the Language
    2. Common Practices
    3. Theoretical Framework

    View full-size slide

  5. 1. Referential Transparency
    2. Pointfree Programming
    3. Algebraic Data Types

    View full-size slide

  6. Referential
    Transparency

    View full-size slide

  7. Referential Transparency
    An expression is referentially transparent if you can
    replace that expression with its corresponding value without
    changing the behavior of the program.

    View full-size slide

  8. Referential Transparency
    function main()
    {
    $i = 41;
    $i++;
    return $i;
    }

    View full-size slide

  9. Referential Transparency
    function main()
    {
    $i = 41;
    $i++; // <- evaluates to 41
    return $i;
    }

    View full-size slide

  10. Referential Transparency
    function main()
    {
    $i = 41;
    41;
    return $i;
    }

    View full-size slide

  11. Referential Transparency
    function main()
    {
    $i = 41;
    $j = $i + 1;
    return $j;
    }

    View full-size slide

  12. Referential Transparency
    function main()
    {
    $i = 41;
    $j = $i + 1; // <- evaluates to 42
    return $j;
    }

    View full-size slide

  13. Referential Transparency
    function main()
    {
    $i = 41;
    $j = 42;
    return $j;
    }

    View full-size slide

  14. Referential Transparency
    Referential transparency means that when you read code, you
    only have to think of the outcome of an expression. You can
    forget about state, and the way that evaluating an
    expression can change that state.

    View full-size slide

  15. 1. Pure Functions
    2. Immutability
    3. Immutable Data Structures
    4. Recursion

    View full-size slide

  16. Pure Functions
    function average($a, $b)
    {
    return ($a + $b) / 2;
    }

    View full-size slide

  17. Immutability
    function average($a, $b)
    {
    $total = 0;
    $total += $a; // <- fail!
    $total += $b; // <- fail!
    return $total / 2;
    }

    View full-size slide

  18. Immutability
    function average($a, $b)
    {
    $total = $a + $b;
    return $total / 2;
    }

    View full-size slide

  19. Immutable Data Structures
    $x = 1;
    $y = 2;
    $p = [0, 2];
    $p[2] = 5; // <- fail

    View full-size slide

  20. Immutable Data Structures
    $xs = [1, [2, [3, null]]];
    head($xs) // <- 1
    tail($xs) // <- [2, [3, null]]
    $empty = null;

    View full-size slide

  21. Recursion
    To understand recursion, you must first understand
    recursion.

    View full-size slide

  22. Recursion
    function average($xs)
    {
    return sum($xs) / length($xs);
    }

    View full-size slide

  23. Recursion
    function length($xs)
    {
    $length = 0;
    foreach ($xs as $x) {
    $length += 1; // <- fail!
    }
    return $length;
    }

    View full-size slide

  24. Recursion
    function sum($xs)
    {
    $sum = 0;
    foreach ($xs as $x) {
    $sum += $x; // <- fail!
    }
    return $sum;
    }

    View full-size slide

  25. Recursion
    function length($xs)
    {
    if ($xs === null) {
    return 0;
    }
    return 1 + length(tail($xs));
    }

    View full-size slide

  26. Recursion
    function sum($xs)
    {
    if ($xs === null) {
    return 0;
    }
    return head($xs) + sum(tail($xs));
    }

    View full-size slide

  27. Recursion
    average($xs)

    View full-size slide

  28. Recursion
    average($xs)

    View full-size slide

  29. Recursion
    average([1, [2, [3, null]]])

    View full-size slide

  30. Recursion
    average([1, [2, [3, null]]])

    View full-size slide

  31. Recursion
    sum([1, [2, [3, null]]]) / length([1, [2, [3, null]]])

    View full-size slide

  32. Recursion
    sum([1, [2, [3, null]]]) / length([1, [2, [3, null]]])

    View full-size slide

  33. Recursion
    (head([1, [2, [3, null]]]) + sum(tail([1, [2, [3, null]]])))
    / (1 + length(tail([1, [2, [3, null]]])))

    View full-size slide

  34. Recursion
    (head([1, [2, [3, null]]]) + sum(tail([1, [2, [3, null]]])))
    / (1 + length(tail([1, [2, [3, null]]])))

    View full-size slide

  35. Recursion
    (1 + sum(tail([1, [2, [3, null]]]))) / (1 + length(tail([1,
    [2, [3, null]]])))

    View full-size slide

  36. Recursion
    (1 + sum(tail([1, [2, [3, null]]]))) / (1 + length(tail([1,
    [2, [3, null]]])))

    View full-size slide

  37. Recursion
    (1 + sum([2, [3, null]])) / (1 + length(tail([1, [2, [3,
    null]]])))

    View full-size slide

  38. Recursion
    (1 + sum([2, [3, null]])) / (1 + length(tail([1, [2, [3,
    null]]])))

    View full-size slide

  39. Recursion
    (1 + sum([2, [3, null]])) / (1 + length([2, [3, null]]))

    View full-size slide

  40. Recursion
    (1 + sum([2, [3, null]])) / (1 + length([2, [3, null]]))

    View full-size slide

  41. Recursion
    (1 + 2 + sum([3, null])) / (1 + 1 + length([3, null]))

    View full-size slide

  42. Recursion
    (1 + 2 + sum([3, null])) / (1 + 1 + length([3, null]))

    View full-size slide

  43. Recursion
    (1 + 2 + 3 + sum(null)) / (1 + 1 + 1 + length(null))

    View full-size slide

  44. Recursion
    (1 + 2 + 3 + sum(null)) / (1 + 1 + 1 + length(null))

    View full-size slide

  45. Recursion
    (1 + 2 + 3 + 0) / (1 + 1 + 1 + 0)

    View full-size slide

  46. Recursion
    (1 + 2 + 3 + 0) / (1 + 1 + 1 + 0)

    View full-size slide

  47. Recursion
    6 / 3

    View full-size slide

  48. Recursion
    6 / 3

    View full-size slide

  49. Recursion
    function sum($xs)
    {
    if ($xs === null) {
    return 0;
    }
    return head($xs) + sum(tail($xs));
    }

    View full-size slide

  50. Recursion
    function sum($xs)
    {
    if ($xs === null) {
    return 0;
    }
    return head($xs) + sum(tail($xs)); // <- recursion
    }

    View full-size slide

  51. Recursion
    function sum($xs, $start)
    {
    if ($xs === null) {
    return $start;
    }
    return sum(tail($xs),
    head($xs) + $start); // <- tail recursion
    }

    View full-size slide

  52. Pointfree
    Programming

    View full-size slide

  53. 1. Currying
    2. Partial Application
    3. Higher Order Functions
    4. Functional Composition

    View full-size slide

  54. Higher Order Functions
    A higher order function is a function that accepts a
    function as one of its parameters and/or returns a function.

    View full-size slide

  55. Higher Order Functions
    function sum(xs) {
    if (xs === null) {
    return 0;
    }
    return head(xs) + sum(tail(xs));
    }

    View full-size slide

  56. Higher Order Functions
    const sum = xs =>
    xs === null ? 0 : head(xs) + sum(tail(xs));

    View full-size slide

  57. Higher Order Functions
    const add = (x, y) =>
    x + y;

    View full-size slide

  58. Higher Order Functions
    const add = x => y => // <- currying
    x + y;

    View full-size slide

  59. Higher Order Functions
    const add = x => y =>
    x + y;
    add(1)(2) // <- evaluates to 3

    View full-size slide

  60. Higher Order Functions
    const add = x => y =>
    x + y;
    add(1) // <- evaluates to y => 1 + y

    View full-size slide

  61. Higher Order Functions
    const add = x => y =>
    x + y;
    add(1) // <- partial application

    View full-size slide

  62. Higher Order Functions
    const add = x => y =>
    x + y;
    add(1) // <- higher order function

    View full-size slide

  63. Higher Order Functions
    const add = x => y =>
    x + y;
    const sum = xs =>
    xs === null ? 0 : add(head(xs))(sum(tail(xs)));

    View full-size slide

  64. Higher Order Functions
    const foldr = f => z => xs =>
    xs === null ? z : f(head(xs))(foldr(f)(z)(tail(xs)))

    View full-size slide

  65. Higher Order Functions
    const foldr = f => z => xs =>
    xs === null ? z : f(head(xs))(foldr(f)(z)(tail(xs)))
    const sum = xs =>
    xs === null ? 0 : add(head(xs))(sum(tail(xs)));

    View full-size slide

  66. Higher Order Functions
    const foldr = f => z => xs =>
    xs === null ? z : f(head(xs))(foldr(f)(z)(tail(xs)))
    const sum = xs =>
    xs === null ? 0 : add(head(xs))(sum(tail(xs)));

    View full-size slide

  67. Higher Order Functions
    const foldr = f => z => xs =>
    xs === null ? z : f(head(xs))(foldr(f)(z)(tail(xs)))
    const sum = xs =>
    xs === null ? 0 : add(head(xs))(sum(tail(xs)));

    View full-size slide

  68. Higher Order Functions
    const foldr = f => z => xs =>
    xs === null ? z : f(head(xs))(foldr(f)(z)(tail(xs)))
    const sum = xs =>
    xs === null ? 0 : add(head(xs))(sum(tail(xs)));

    View full-size slide

  69. Higher Order Functions
    const foldr = f => z => xs =>
    xs === null ? z : f(head(xs))(foldr(f)(z)(tail(xs)))
    const sum = foldr(add)(0);

    View full-size slide

  70. Higher Order Functions
    const map = f => xs =>
    xs === null ? null : [f(head(xs)), map(f)(tail(xs))];
    const compose = f => g =>
    x => f(g(x)); // <- functional composition
    const constant = x => y =>
    x;

    View full-size slide

  71. Higher Order Functions
    const ones = map(constant(1));
    const length = compose(sum)(ones);

    View full-size slide

  72. Pointfree Programming
    const sum = foldr(add)(0);
    const ones = map(constant(1));
    const length = compose(sum)(ones);
    // not one single parameter

    View full-size slide

  73. Pointfree Programming
    Topology (a branch of mathematics) works with spaces
    composed of points, and functions between those spaces. So a
    pointfree definition of a function is one which does not
    explicitly mention the points (values) of the space on which
    the function acts.

    View full-size slide

  74. Algebraic
    Data Types

    View full-size slide

  75. Algebraic Data Types
    Just like there are rules for manipulating numbers, there
    are rules for manipulating types.

    View full-size slide

  76. 1. Sum Types
    2. Product Types
    3. Type Constructors
    4. Recursive Type Definitions
    5. Pattern Matching

    View full-size slide

  77. Sum Types
    data Bool = True | False
    not :: Bool -> Bool
    not True = False
    not False = True

    View full-size slide

  78. Product Types
    data Point = Point Int Int
    translate :: Point -> Point -> Point
    translate (Point dx dy) (Point x y) =
    Point (x + dx) (y + dy)

    View full-size slide

  79. Type Constructors
    data Maybe a = Nothing | Just a
    isNothing :: Maybe a -> Bool
    isNothing (Just a) = False
    isNothing Nothing = True

    View full-size slide

  80. Recursive Type Definitions
    data List a = Nil | Cons a (List a)
    length :: List a -> Int
    length Nil = 0
    length (Cons x xs) = 1 + length xs

    View full-size slide

  81. Pattern Matching
    translate (Point dx dy) (Point x y) =
    Point (x + dx) (y + dy)
    length Nil = 0
    length (Cons x xs) = 1 + length xs

    View full-size slide

  82. 6. Hindley-Milner Type System

    View full-size slide

  83. Hindley-Milner Type System
    The Hindley-Milner Type System is a system that allows you
    to do type inference on lambda calculus, in order to derive
    the most generic type of every expression in a program.

    View full-size slide

  84. Type Inference
    data List a = Nil | Cons a (List a)
    -- length :: List a -> Int
    length Nil = 0
    length (Cons x xs) = 1 + length xs

    View full-size slide

  85. Type Inference
    data List a = Nil | Cons a (List a)
    -- length :: List a -> Int
    length Nil = 0
    length (Cons x xs) = "1" ++ length xs -- <- oops
    -- No instance for (Num [Char]) arising from the literal ‘0’

    View full-size slide

  86. Type Inference
    data List a = Nil | Cons a (List a)
    length :: List a -> Int
    length Nil = 0
    length Cons x xs = "1" ++ length xs -- <- oops
    -- Couldn't match expected type ‘Int’
    -- with actual type ‘[Char]’

    View full-size slide

  87. Type Inference
    data List a = Nil | Cons a (List a)
    length :: List a -> Int
    length Nil = 0
    length Cons x xs = length -- <- totale nonsense
    -- Couldn't match expected type ‘Int’
    -- with actual type ‘List a0 -> Int’

    View full-size slide

  88. Type Inference
    the algorithm (roughly):
    1. assign type variables to all expressions (both left and
    right of an ‘=’)
    2. start at the top
    3. move to the next piece of code that imposes a constraint
    4. unify the two type variables
    5. go back to step 3, until you reach the bottom

    View full-size slide

  89. Type Inference
    constraints:
    ● the left and right hand side of ‘=’ must have the same
    type
    ● the result of ‘+’ has the same type as the expressions on
    either side
    ● applying a function with type a0 -> a1 is only valid on a
    parameter of type a0
    ● applying a function with type a0 -> a1 always produces a
    result of type a1

    View full-size slide

  90. Type Inference
    unifying type variables:
    ● if a0 = Int
    and a1 = a0
    then a1 = Int
    ● if a2 = Maybe Int
    and a3 = Maybe a4
    and a2 = a3
    then a4 = Int

    View full-size slide

  91. Hindley-Milner Type System
    (->) is a Type Constructor

    View full-size slide

  92. Category
    Theory

    View full-size slide

  93. Monads
    Once you understand monads for yourself, you lose the
    ability to explain them to others. – Douglas Crockford

    View full-size slide

  94. 1. Functors
    2. Monoid
    3. Applicatives
    4. Monads

    View full-size slide

  95. 1. Functors
    2. Monoid
    3. Applicatives
    4. Monads

    View full-size slide

  96. The Maybe Functor
    class Functor f where
    fmap :: (a -> b) -> f a -> f b
    data Maybe a = Nothing | Just a
    instance Functor Maybe where
    fmap _ Nothing = Nothing
    fmap f (Just a) = Just (f a)

    View full-size slide

  97. The Maybe Functor
    isEven x = x `mod` == 0
    fmap isEven (Just 1) -- Just False
    fmap isEven Nothing -- Nothing

    View full-size slide

  98. The Maybe Functor
    isEven x = x `mod` == 0
    maybeEven = fmap isEven
    maybeEven (Just 1) -- Just False
    maybeEven Nothing -- Nothing

    View full-size slide

  99. 0. Category Theory

    View full-size slide

  100. Category Theory for Programmers
    Bartosz Milewski

    View full-size slide

  101. Category Theory

    View full-size slide

  102. Derp
    examples of categories:
    ● Grp – a category with groups for objects and group
    homomorphisms as morphisms (see also group theory)
    ● Set – the category whose objects are sets, and where
    functions form the morphisms

    View full-size slide

  103. Functors
    A functor is a mapping from one category to another.

    View full-size slide

  104. Functor Laws
    category theory demands the following:
    fmap id = id
    fmap (p . q) = (fmap p) . (fmap q)

    View full-size slide

  105. Functor Laws

    View full-size slide

  106. Functor Laws

    View full-size slide

  107. The Maybe Functor
    -- fmap id = id
    instance Functor Maybe where
    fmap _ Nothing = Nothing
    fmap f (Just a) = Just (f a)

    View full-size slide

  108. The Maybe Functor
    -- fmap id Nothing = id Nothing
    -- Nothing = Nothing
    instance Functor Maybe where
    fmap _ Nothing = Nothing
    fmap f (Just a) = Just (f a)

    View full-size slide

  109. The Maybe Functor
    -- fmap id (Just a) = id (Just a)
    -- Just (id a) = Just a
    -- Just a = Just a
    instance Functor Maybe where
    fmap _ Nothing = Nothing
    fmap f (Just a) = Just (f a)

    View full-size slide

  110. The Maybe Functor
    -- fmap (p . q) = (fmap p) . (fmap q)
    instance Functor Maybe where
    fmap _ Nothing = Nothing
    fmap f (Just a) = Just (f a)

    View full-size slide

  111. The Maybe Functor
    -- fmap (p . q) Nothing = ((fmap p) . (fmap q)) Nothing
    -- Nothing = (fmap p) ((fmap q) Nothing)
    -- Nothing = (fmap p) Nothing
    -- Nothing = Nothing
    instance Functor Maybe where
    fmap _ Nothing = Nothing
    fmap f (Just a) = Just (f a)

    View full-size slide

  112. The Maybe Functor
    -- fmap (p . q) (Just a) = ((fmap p) . (fmap q)) (Just a)
    -- Just ((p . q) a) = (fmap p) ((fmap q) (Just a))
    -- Just (p (q a)) = (fmap p) (Just (q a))
    -- Just (p (q a)) = Just (p (q a))
    instance Functor Maybe where
    fmap _ Nothing = Nothing
    fmap f (Just a) = Just (f a)

    View full-size slide

  113. Category Theory

    View full-size slide

  114. 1. Referential Transparency
    2. Pointfree Programming
    3. Algebraic Data Types

    View full-size slide

  115. Thnx
    @scataco

    View full-size slide