Functional Programming for "Dummies"

Ffbc1edf730289e764d67474349a8021?s=47 scato
July 05, 2017

Functional Programming for "Dummies"

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

Ffbc1edf730289e764d67474349a8021?s=128

scato

July 05, 2017
Tweet

Transcript

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

    Computer Science
  2. Functional Programming is...

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

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

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

  6. Referential Transparency

  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.
  8. Referential Transparency function main() { $i = 41; $i++; return

    $i; }
  9. Referential Transparency function main() { $i = 41; $i++; //

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

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

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

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

    42; return $j; }
  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.
  15. 1. Pure Functions 2. Immutability 3. Immutable Data Structures 4.

    Recursion
  16. Pure Functions function average($a, $b) { return ($a + $b)

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

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

    return $total / 2; }
  19. Immutable Data Structures $x = 1; $y = 2; $p

    = [0, 2]; $p[2] = 5; // <- fail
  20. Immutable Data Structures $xs = [1, [2, [3, null]]]; head($xs)

    // <- 1 tail($xs) // <- [2, [3, null]] $empty = null;
  21. Recursion To understand recursion, you must first understand recursion.

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

  23. Recursion function length($xs) { $length = 0; foreach ($xs as

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

    $x) { $sum += $x; // <- fail! } return $sum; }
  25. Recursion function length($xs) { if ($xs === null) { return

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

    0; } return head($xs) + sum(tail($xs)); }
  27. Recursion average($xs)

  28. Recursion average($xs)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    + 1 + 1 + 0)
  47. Recursion 6 / 3

  48. Recursion 6 / 3

  49. Recursion 2

  50. Recursion 2

  51. Recursion function sum($xs) { if ($xs === null) { return

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

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

    return $start; } return sum(tail($xs), head($xs) + $start); // <- tail recursion }
  54. Recursion

  55. Pointfree Programming

  56. 1. Currying 2. Partial Application 3. Higher Order Functions 4.

    Functional Composition
  57. Higher Order Functions A higher order function is a function

    that accepts a function as one of its parameters and/or returns a function.
  58. Higher Order Functions function sum(xs) { if (xs === null)

    { return 0; } return head(xs) + sum(tail(xs)); }
  59. Higher Order Functions const sum = xs => xs ===

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

    + y;
  61. Higher Order Functions const add = x => y =>

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

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

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

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

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

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

    xs => xs === null ? z : f(head(xs))(foldr(f)(z)(tail(xs)))
  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)));
  69. 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)));
  70. 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)));
  71. 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)));
  72. Higher Order Functions const foldr = f => z =>

    xs => xs === null ? z : f(head(xs))(foldr(f)(z)(tail(xs))) const sum = foldr(add)(0);
  73. 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;
  74. Higher Order Functions const ones = map(constant(1)); const length =

    compose(sum)(ones);
  75. Pointfree Programming const sum = foldr(add)(0); const ones = map(constant(1));

    const length = compose(sum)(ones); // not one single parameter
  76. 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.
  77. Algebraic Data Types

  78. Algebraic Data Types Just like there are rules for manipulating

    numbers, there are rules for manipulating types.
  79. 1. Sum Types 2. Product Types 3. Type Constructors 4.

    Recursive Type Definitions 5. Pattern Matching
  80. Sum Types data Bool = True | False not ::

    Bool -> Bool not True = False not False = True
  81. Product Types data Point = Point Int Int translate ::

    Point -> Point -> Point translate (Point dx dy) (Point x y) = Point (x + dx) (y + dy)
  82. Type Constructors data Maybe a = Nothing | Just a

    isNothing :: Maybe a -> Bool isNothing (Just a) = False isNothing Nothing = True
  83. 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
  84. Pattern Matching translate (Point dx dy) (Point x y) =

    Point (x + dx) (y + dy) length Nil = 0 length (Cons x xs) = 1 + length xs
  85. 6. Hindley-Milner Type System

  86. 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.
  87. Type Inference data List a = Nil | Cons a

    (List a) -- length :: List a -> Int length Nil = 0 length (Cons x xs) = 1 + length xs
  88. 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’
  89. 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]’
  90. 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’
  91. 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
  92. 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
  93. 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
  94. Hindley-Milner Type System (->) is a Type Constructor

  95. Category Theory

  96. Monads Once you understand monads for yourself, you lose the

    ability to explain them to others. – Douglas Crockford
  97. 1. Functors 2. Monoid 3. Applicatives 4. Monads

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

  99. 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)
  100. The Maybe Functor isEven x = x `mod` == 0

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

    maybeEven = fmap isEven maybeEven (Just 1) -- Just False maybeEven Nothing -- Nothing
  102. 0. Category Theory

  103. Category Theory for Programmers Bartosz Milewski

  104. Category Theory

  105. 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
  106. Functors A functor is a mapping from one category to

    another.
  107. Functors

  108. Functors

  109. Functor Laws category theory demands the following: fmap id =

    id fmap (p . q) = (fmap p) . (fmap q)
  110. Functor Laws

  111. Functor Laws

  112. The Maybe Functor -- fmap id = id instance Functor

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

    -- Nothing = Nothing instance Functor Maybe where fmap _ Nothing = Nothing fmap f (Just a) = Just (f a)
  114. 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)
  115. The Maybe Functor -- fmap (p . q) = (fmap

    p) . (fmap q) instance Functor Maybe where fmap _ Nothing = Nothing fmap f (Just a) = Just (f a)
  116. 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)
  117. 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)
  118. Category Theory

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

  120. Thnx @scataco