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

Functional Programming in PHP

Functional Programming in PHP

It’s becoming increasingly difficult to ignore the term "Functional Programming" while reading online discussions about programming languages or programming in general. People talking about FP routinely use terms that can be strange and unfamiliar to developers coming from the imperative world.

So what exactly is Functional Programming? Where does it come from? How does it differ from the programming I already know?

This talk will try to answer these questions by weaving seemingly unrelated concepts into a (hopefully) coherent story of FP, using PHP as the vehicle of expressing these ideas. The side effect (pun intended) of having a grasp of FP will make you a better developer.

Video:
https://www.youtube.com/watch?v=pWQV1x3YIJM&t=1m0s

Code:
https://github.com/pwm/fp-php-talk

Zsolt Szende

June 01, 2017
Tweet

More Decks by Zsolt Szende

Other Decks in Programming

Transcript

  1. Functional Programming
    … in PHP
    (Warning: Contains traces of Math)

    View Slide

  2. What is
    Functional Programming?

    View Slide

  3. Functional Programming is
    programming with functions.

    View Slide

  4. View Slide

  5. What is a function?

    View Slide

  6. Marc
    Claire
    Adam
    Nora
    Coffee
    Tea
    A B

    View Slide

  7. Marc
    Claire
    Adam
    Nora
    Coffee
    Tea
    A B

    View Slide

  8. Marc
    Claire
    Adam
    Nora
    Coffee
    Tea
    A B

    View Slide

  9. Marc
    Claire
    Adam
    Nora
    Coffee
    Tea
    f : A ! B
    A B
    Functions, like in mathematics

    View Slide

  10. Functions in code

    View Slide

  11. Rule #1
    Always return the same
    output for the same input.

    View Slide

  12. Rule #1
    Always return the same
    output for the same input.
    Rule #2
    Do nothing else aka. no
    side effects.

    View Slide

  13. Turns out we do have a name
    for functions in programming.

    View Slide

  14. Turns out we do have a name
    for functions in programming.
    We call them
    pure functions

    View Slide

  15. // Int -> Int
    function increment(int $x): int {
    return $x + 1;
    }
    echo increment(2); // 3
    echo increment(2); // 3
    // String -> String
    function ask($s) {
    return $s.’?';
    }
    echo ask('I am pure'); // I am pure?
    echo ask('I am pure'); // I am pure?
    Pure functions
    Our sets from earlier. Think of it as the function’s interface.

    View Slide

  16. // Int -> Int
    function constant($x) {
    return 1;
    }
    echo constant(4); // 1
    echo constant(4); // 1
    // String -> Bool
    function startsWithP($s) {
    return $s[0] === 'P';
    }
    echo startsWithP('Pure'); // True
    echo startsWithP('Pure'); // True
    echo startsWithP('Impure'); // False
    echo startsWithP('Impure'); // False
    Pure functions

    View Slide

  17. Violating rule #1
    // Int -> Int
    function f($x) {
    return random_int(0, $x);
    }
    echo f(10); // 4
    echo f(10); // 7
    // Int -> Int
    function g($x) {
    global $y;
    return $x + $y;
    }
    $y = 1;
    echo g(2); // 3
    $y = 5;
    echo g(2); // 7

    View Slide

  18. // String -> String
    function f($s) {
    echo 'I am not pure anymore :(';
    return $s;
    }
    // String -> String
    function g($s) {
    file_put_contents(
    '/tmp/some.log',
    'I am not pure anymore :(’
    );
    return $s;
    }
    Violating rule #2

    View Slide

  19. What can we do if we only
    have functions?

    View Slide

  20. View Slide

  21. f
    (
    x
    ) =
    x
    + 1

    View Slide

  22. We are used to seeing
    functions written like this.
    f
    (
    x
    ) =
    x
    + 1

    View Slide

  23. We are used to seeing
    functions written like this.
    f
    (
    x
    ) =
    x
    + 1
    f
    :
    x
    !
    x
    + 1
    But we don’t need x to
    be able to talk about f.

    View Slide

  24. f
    (
    x
    ) =
    x
    + 1
    x
    !
    x
    + 1
    We are used to seeing
    functions written like this.
    In fact we don’t need to
    label it f or anything at all.

    View Slide

  25. f
    (
    x
    ) =
    x
    + 1
    x
    !
    x
    + 1
    This is called a
    lambda expression.

    View Slide

  26. function f() {
    return function ($x) {
    return $x + 1;
    };
    }
    Lambdas

    View Slide

  27. function f() {
    return function ($x) {
    return $x + 1;
    };
    }
    Lambdas
    At this point it has no label
    referring to it, it is just a value.
    f, when called, returns our \x —> x + 1
    from the previous slide

    View Slide

  28. function f() {
    return function ($x) {
    return $x + 1;
    };
    }
    $aLabel = f();
    echo $aLabel(1); // 2
    Lambdas
    Calling f returns our lambda, which
    will now be bound to a label
    (\x —> x + 1)(1) = 1 + 1 = 2
    At this point it has no label
    referring to it, it is just a value.
    f, when called, returns our \x —> x + 1
    from the previous slide

    View Slide

  29. Lambdas
    function f($g, $x) {
    return $g($x);
    }
    echo f(function ($x) { return $x + 1; }, 1); // 2
    Hi there, I'm a lambda being passed around…

    View Slide

  30. You have just witnessed
    Higher-order functions

    View Slide

  31. You said only functions,
    but there was + and 1 …

    View Slide

  32. Alonzo Church

    View Slide

  33. Lambda calculus
    $c0 = function ($s, $z) { return $z; };
    $c1 = function ($s, $z) { return $s($z); };
    $c2 = function ($s, $z) { return $s($s($z)); };
    // ...
    $c2i = function ($n) {
    return $n(function ($x) { return $x + 1; }, 0);
    };
    assert($c2i($c0) === 0);
    assert($c2i($c1) === 1);
    assert($c2i($c2) === 2);
    $plus = function ($m, $n) {
    return function ($s, $z) use ($m, $n) {
    return $m($s, $n($s, $z));
    };
    };
    assert($c2i($plus($c1, $c2)) === 3);
    // ...

    View Slide

  34. Lambda calculus
    $true = function ($t, $f) { return $t; };
    $false = function ($t, $f) { return $f; };
    assert($true ('T', 'F') === 'T');
    assert($false('T', 'F') === 'F');
    $and = function ($b1, $b2) { return $b1($b2, $b1); };
    $or = function ($b1, $b2) { return $b1($b1, $b2); };
    assert($and($true, $true) ('T', 'F') === 'T');
    assert($and($true, $false) ('T', 'F') === 'F');
    assert($and($false, $true) ('T', 'F') === 'F');
    assert($and($false, $false)('T', 'F') === 'F');
    assert($or($true, $true) ('T', 'F') === 'T');
    assert($or($true, $false) ('T', 'F') === 'T');
    assert($or($false, $true) ('T', 'F') === 'T');
    assert($or($false, $false)('T', 'F') === 'F');
    $if = function ($p, $t, $f) { return $p($t, $f); };
    assert($if($or($false, $and($true, $true)), 'T', 'F') === 'T');

    View Slide

  35. To save our sanity for the
    rest of the talk we will
    assume that we have these
    basic types :)

    View Slide

  36. Functions as building
    blocks

    View Slide

  37. Water
    Juice
    Beer
    Wine
    Marc
    Claire
    Adam
    Nora
    Ed
    A B
    f : A ! B

    View Slide

  38. Water
    Juice
    Beer
    Wine
    Alcoholic
    Non-Alcoholic
    Marc
    Claire
    Adam
    Nora
    Ed
    A B C
    f : A ! B g : B ! C

    View Slide

  39. Water
    Juice
    Beer
    Wine
    Alcoholic
    Non-Alcoholic
    Marc
    Claire
    Adam
    Nora
    Ed
    A B C
    f : A ! B g : B ! C
    g f : A ! C

    View Slide

  40. Water
    Juice
    Beer
    Wine
    Alcoholic
    Non-Alcoholic
    Marc
    Claire
    Adam
    Nora
    Ed
    A B C
    f : A ! B g : B ! C
    g f : A ! C
    Meet little circle,
    pronounced “after”
    g f
    =
    x
    !
    g
    (
    f
    (
    x
    ))

    View Slide

  41. This is called
    composition

    View Slide

  42. View Slide

  43. Composition in code

    View Slide

  44. $f = function ($s) { return 'f'.$s; };
    $g = function ($s) { return 'g'.$s; };
    echo $g($f('')); // gf
    echo $g($f('')); // gf
    echo $g($f(' !!!')); // gf !!!
    echo $g($f(' !!!')); // gf !!!
    Composition

    View Slide

  45. Huh, but where is ?
    g f

    View Slide

  46. g f
    =
    x
    !
    g
    (
    f
    (
    x
    ))
    To express “g little circle f” as a function
    we need to define little circle.

    View Slide

  47. function o($g, $f) {
    return function ($x) {
    return $g($f($x));
    };
    }
    Composition

    View Slide

  48. function o($g, $f) {
    return function ($x) {
    return $g($f($x));
    };
    }
    $f = function ($s) { return 'f'.$s; };
    $g = function ($s) { return 'g'.$s; };
    $gf = o($g, $f);
    Composition
    g f
    =
    x
    !
    g
    (
    f
    (
    x
    ))

    View Slide

  49. function o($g, $f) {
    return function ($x) {
    return $g($f($x));
    };
    }
    $f = function ($s) { return 'f'.$s; };
    $g = function ($s) { return 'g'.$s; };
    $gf = o($g, $f);
    echo $gf(''); // Error...
    Composition
    g f
    =
    x
    !
    g
    (
    f
    (
    x
    ))

    View Slide

  50. Closure
    an important
    implementation detail

    View Slide

  51. $y = 1;
    function f($x) {
    return $x + $y;
    }
    Closure #1

    View Slide

  52. $y = 1;
    function f($x) {
    return $x + $y;
    }
    echo f(1); // Undefined variable: y
    Closure #1
    $y was declared in the outermost scope, aka. the global scope
    In PHP $y is not defined in this scope.
    PHP is lexically scoped using functions
    as boundaries. Inside f there's a new
    scope that’s local to f.

    View Slide

  53. function f() {
    $y = 1;
    return function ($x) {
    return $x + $y;
    };
    }
    Closure #2

    View Slide

  54. function f() {
    $y = 1;
    return function ($x) {
    return $x + $y;
    };
    }
    echo f()(1); // Undefined variable: y
    Closure #2
    $y is now defined in the scope local to f
    But we don’t have access
    to $y inside this lambda,
    as it has its own scope.

    View Slide

  55. function f() {
    $y = 1;
    return function ($x) use ($y) {
    return $x + $y;
    };
    }
    Closure #3

    View Slide

  56. function f() {
    $y = 1;
    return function ($x) use ($y) {
    return $x + $y;
    };
    }
    echo f()(1); // 2
    Closure #3
    A free variable whose value gets
    captured when we call f.
    In PHP we must explicitly state what we
    want to capture in from the enclosing
    scope to achieve closure.
    This is done by the use() statement.
    Closure !

    View Slide

  57. Fixing little circle…

    View Slide

  58. function o($g, $f) {
    return function ($x) use ($g, $f) {
    return $g($f($x));
    };
    }
    Composition

    View Slide

  59. function o($g, $f) {
    return function ($x) use ($g, $f) {
    return $g($f($x));
    };
    }
    $f = function ($s) { return 'f'.$s; };
    $g = function ($s) { return 'g'.$s; };
    $gf = o($g, $f);
    echo $gf(''); // gf
    echo $gf(''); // gf
    echo $gf(' !!!'); // gf !!!
    echo $gf(' !!!'); // gf !!!
    Composition
    g f
    =
    x
    !
    g
    (
    f
    (
    x
    ))

    View Slide

  60. View Slide

  61. What about composing
    functions with multiple
    arguments?

    View Slide

  62. 1 + 1 = 2

    View Slide

  63. “+” is a binary function ie. it takes 2 arguments.
    Could call it “f” instead of “+” if we wanted to.
    + : (N, N) ! N

    View Slide

  64. x
    ! (
    y
    !
    x
    +
    y
    )
    Or is it a unary function that takes an x and returns
    a function, that takes an y and returns x + y?

    View Slide

  65. 1
    2
    3
    x
    ! 1 +
    x
    x
    ! 2 +
    x
    x
    ! 3 +
    x
    ... ...
    + : N ! N ⇥ N
    N ⇥ N
    N

    View Slide

  66. This is called
    currying

    View Slide

  67. Currying
    function normal_plus($x, $y) {
    return $x + $y;
    };
    echo normal_plus(1, 2); // 3

    View Slide

  68. Currying
    function normal_plus($x, $y) {
    return $x + $y;
    };
    echo normal_plus(1, 2); // 3
    function curried_plus($x) {
    return function ($y) use ($x) {
    return $x + $y;
    };
    };
    echo curried_plus(1)(2); // 3

    View Slide

  69. Currying also means
    injecting behaviour

    View Slide

  70. function plus($x) {
    return function ($y) use ($x) {
    return $x + $y;
    };
    };
    $addOne = plus(1);
    echo $addOne(1); // 2
    Currying
    ( y ! 1 + y)(1) = 2
    (
    x
    ! (
    y
    !
    x
    +
    y
    ))(1) =
    y
    ! 1 +
    y

    View Slide

  71. Now we can compose
    functions with any arity!

    View Slide

  72. Currying
    function o($g, $f) {
    return function ($x) use ($g, $f) {
    return $g($f($x));
    };
    }
    function plus($x) {
    return function ($y) use ($x) {
    return $x + $y;
    };
    };
    $addTwo = o(plus(1), plus(1));
    echo $addTwo(1); // 3

    View Slide

  73. Hm, but little circle still
    takes two arguments …

    View Slide

  74. =
    g
    ! (
    f
    ! (
    x
    !
    g
    (
    f
    (
    x
    ))))
    Function that takes a function g, returns a function that
    takes a function f, returns a function that takes x
    and returns g(f(x)).

    View Slide

  75. Currying
    function o($g) {
    return function ($f) use ($g) {
    return function ($x) use ($g, $f) {
    return $g($f($x));
    };
    };
    }
    function plus(int $x) {
    return function (int $y) use ($x) {
    return $x + $y;
    };
    };
    echo o(plus(1))(plus(1))(1); // 3
    Notice how the number of
    captured variables grow.

    View Slide

  76. Currying is tedious, we
    need some syntactic sugar

    View Slide

  77. Currying
    $normalPlus = function($x, $y) { return $x + $y; };
    $curriedPlus = curry($normalPlus);
    assert($normalPlus(1, 1) === $curriedPlus(1)(1)); // 2 === 2

    View Slide

  78. Currying
    function curry(callable $fn, ...$args): Closure {
    return function (...$partialArgs) use ($fn, $args) {
    return (function ($args) use ($fn) {
    return count($args) < (new ReflectionFunction($fn))
    ->getNumberOfRequiredParameters()
    ? curry($fn, ...$args)
    : $fn(...$args);
    })(array_merge($args, $partialArgs));
    };
    }
    $normalPlus = function($x, $y) { return $x + $y; };
    $curriedPlus = curry($normalPlus);
    assert($normalPlus(1, 1) === $curriedPlus(1)(1)); // 2 === 2
    Do not panic !

    View Slide

  79. Composition has
    interesting properties

    View Slide

  80. f g h
    A B C D
    h g : B ! D
    g f : A ! C

    View Slide

  81. f g h
    A B C D
    g f : A ! C
    h g : B ! D
    h (g f) : A ! D

    View Slide

  82. f g h
    A B C D
    h g : B ! D
    g f : A ! C
    (h g) f : A ! D

    View Slide

  83. f g h
    A B C D
    h (g f)=(h g) f
    Function composition is associative
    g f : A ! C
    h g : B ! D

    View Slide

  84. $o = curry(function ($g, $f) {
    return function ($x) use ($g, $f) {
    return $g($f($x));
    };
    });
    $f = function ($s) { return 'f'.$s; };
    $g = function ($s) { return 'g'.$s; };
    $h = function ($s) { return 'h'.$s; };
    $gf = $o($g)($f); // g o f
    $hg = $o($h)($g); // h o g
    $h_gf = $o($h)($gf); // h o (g o f)
    $hg_f = $o($hg)($f); // (h o g) o f
    // h o (g o f) = (h o g) o f
    assert($h_gf('') === $hg_f('')); // 'hgf' === 'hgf'
    Associativity of composition

    View Slide

  85. idA : A ! A
    f : A ! B
    A B
    idB : B ! B
    g : B ! A

    View Slide

  86. idA : A ! A
    f : A ! B
    A B
    idB : B ! B
    g : B ! A
    f idA : A ! B

    View Slide

  87. idA : A ! A
    f : A ! B
    A B
    idB : B ! B
    g : B ! A
    idB f : A ! B

    View Slide

  88. idA : A ! A
    f : A ! B
    A B
    idB : B ! B
    g : B ! A
    g idB : B ! A

    View Slide

  89. idA : A ! A
    f : A ! B
    A B
    idB : B ! B
    g : B ! A
    idA g : B ! A

    View Slide

  90. idA : A ! A
    f : A ! B
    A B
    idB : B ! B
    g : B ! A
    f idA = f = idB f
    g idB = g = idA g
    The Identity function aka.
    the function that does nothing

    View Slide

  91. $o = curry(function ($g, $f) {
    return function ($x) use ($g, $f) {
    return $g($f($x));
    };
    });
    $id = function ($x) { return $x; };
    $f = function ($s) { return 'f'.$s; };
    $g = function ($s) { return 'g'.$s; };
    // f = f o id
    assert($f('') === $o($f)($id)(‘’)); // 'f' === 'f'
    // f = id o f
    assert($f('') === $o($id)($f)(‘’)); // 'f' === ‘f'
    // g = g o id
    assert($g('') === $o($g)($id)(‘’)); // 'g' === 'g'
    // g = id o g
    assert($g('') === $o($id)($g)(‘’)); // 'g' === 'g'
    Identity of composition

    View Slide

  92. If there is one there is many.
    Working with lists.

    View Slide

  93. Map
    $map = curry('array_map');
    $addOne = function ($x) { return $x + 1; };
    $addOneToList = $map($addOne);
    print_r($addOneToList([1, 2, 3, 4, 5])); // [2, 3, 4, 5, 6]

    View Slide

  94. Filter
    Behaviour first
    $filter = curry(function ($f, $l) {
    return array_filter($l, $f);
    });
    $isEven = function ($x) { return $x % 2 === 0; };
    $filterEven = $filter($isEven);
    print_r($filterEven([1, 2, 3, 4, 5])); // [2, 4]
    Data (the list) last

    View Slide

  95. Fold
    $fold = curry(function ($f, $v, $l) {
    return array_reduce($l, $f, $v);
    });
    $plus = curry(function ($x, $y) { return $x + $y; });
    $sum = $fold($plus)(0);
    echo $sum([1, 2, 3, 4, 5]); // 15
    List
    Operator Seed value
    [1, 2, 3, 4, 5] —> ((((0 + 1) + 2) + 3) + 4) + 5 = 15

    View Slide

  96. Fold is the essence of
    recursion.

    View Slide

  97. Right fold and Left fold
    $plus = curry(function ($x, $y) { return $x + $y; });
    $sumRight = $foldr($plus)(0);
    $sumLeft = $foldl($plus)(0);
    assert($sumRight([1, 2, 3]) === $sumLeft([1, 2, 3])); // 6 = 6
    ((0 + 1) + 2) + 3 = 1 + (2 + (3 + 0))

    View Slide

  98. Right fold and Left fold
    $foldr = curry(function ($f, $v, $l) use (&$foldr) {
    return count($l) > 0
    ? $f($l[0])($foldr($f)($v)(array_slice($l, 1)))
    : $v;
    });
    $foldl = curry(function ($f, $v, $l) use (&$foldl) {
    return count($l) > 0
    ? $foldl($f)($f($v)($l[0]))(array_slice($l, 1))
    : $v;
    });
    $plus = curry(function ($x, $y) { return $x + $y; });
    $sumRight = $foldr($plus)(0);
    $sumLeft = $foldl($plus)(0);
    assert($sumRight([1, 2, 3]) === $sumLeft([1, 2, 3])); // 6 = 6
    Tiny white lie
    for the sake
    our sanity
    ((0 + 1) + 2) + 3 = 1 + (2 + (3 + 0))

    View Slide

  99. Map and Filter with Fold
    $map = curry(function ($f, $l) use ($foldr) {
    return $foldr(curry(function ($x, $v) use ($f) {
    return array_merge([$f($x)], $v);
    }))([])($l);
    });
    $filter = curry(function ($p, $l) use ($foldr) {
    return $foldr(curry(function ($x, $v) use ($p) {
    return $p($x) ? array_merge([$x], $v) : $v;
    }))([])($l);
    });
    $even = $filter(function ($x) { return $x % 2 === 0; });
    $add1 = $map(function ($x) { return $x + 1; });
    $sum = $foldr(curry(function ($x, $y) { return $x + $y; }))(0);
    assert($sum($add1($even([1, 2, 3, 4]))) === 8);

    View Slide

  100. What about composing
    a list of functions?

    View Slide

  101. $id = function ($x) { return $x; };
    $o = curry(function ($g, $f) {
    return function ($x) use ($g, $f) {
    return $g($f($x));
    };
    });
    $foldr = curry(function ($f, $v, $l) use (&$foldr) {
    return count($l) > 0
    ? $f($l[0])($foldr($f)($v)(array_slice($l, 1)))
    : $v;
    });
    Composition

    View Slide

  102. $id = function ($x) { return $x; };
    $o = curry(function ($g, $f) {
    return function ($x) use ($g, $f) {
    return $g($f($x));
    };
    });
    $foldr = curry(function ($f, $v, $l) use (&$foldr) {
    return count($l) > 0
    ? $f($l[0])($foldr($f)($v)(array_slice($l, 1)))
    : $v;
    });
    $compose = $foldr($o)($id);
    Composition

    View Slide

  103. $id = function ($x) { return $x; };
    $o = curry(function ($g, $f) {
    return function ($x) use ($g, $f) {
    return $g($f($x));
    };
    });
    $foldr = curry(function ($f, $v, $l) use (&$foldr) {
    return count($l) > 0
    ? $f($l[0])($foldr($f)($v)(array_slice($l, 1)))
    : $v;
    });
    $compose = $foldr($o)($id);
    $f = function ($s) { return 'f'.$s; };
    $g = function ($s) { return 'g'.$s; };
    $h = function ($s) { return 'h'.$s; };
    $hgf = $compose([$h, $g, $f]);
    assert($hgf('') === 'hgf'); // 'hgf' === 'hgf'
    Composition

    View Slide

  104. Building things

    View Slide

  105. $plus = curry(function ($x, $y) { return $x + $y; });
    $sum = $foldr($plus)(0);
    echo $sum([1, 2, 3, 4, 5]); // 15
    Building things #1

    View Slide

  106. $plus = curry(function ($x, $y) { return $x + $y; });
    $sum = $foldr($plus)(0);
    echo $sum([1, 2, 3, 4, 5]); // 15
    $matrix = [
    [1, 1, 1, 1, 1],
    [2, 2, 2, 2, 2],
    [3, 3, 3, 3, 3],
    [4, 4, 4, 4, 4],
    [5, 5, 5, 5, 5],
    ];
    Building things #1

    View Slide

  107. $plus = curry(function ($x, $y) { return $x + $y; });
    $sum = $foldr($plus)(0);
    echo $sum([1, 2, 3, 4, 5]); // 15
    $matrix = [
    [1, 1, 1, 1, 1],
    [2, 2, 2, 2, 2],
    [3, 3, 3, 3, 3],
    [4, 4, 4, 4, 4],
    [5, 5, 5, 5, 5],
    ];
    $sumMatrix = $o($sum)($map($sum));
    echo $sumMatrix($matrix); // 75
    Building things #1

    View Slide

  108. $plus = curry(function ($x, $y) { return $x + $y; });
    $sum = $foldr($plus)(0);
    echo $sum([1, 2, 3, 4, 5]); // 15
    $matrix = [
    [1, 1, 1, 1, 1],
    [2, 2, 2, 2, 2],
    [3, 3, 3, 3, 3],
    [4, 4, 4, 4, 4],
    [5, 5, 5, 5, 5],
    ];
    $sumMatrix = $o($sum)($map($sum));
    echo $sumMatrix($matrix); // 75
    $addOneToMatrix = $map($map($plus(1)));
    echo $sumMatrix($addOneToMatrix($matrix)); // 100
    Building things #1

    View Slide

  109. $initials = ???
    echo $initials('This is rather cool :)'); // T I R C
    Building things #2

    View Slide

  110. $explode = curry('explode');
    $implode = curry('implode');
    $match = curry('preg_match');
    $head = function ($s) { return $s[0]; };
    $isWord = $match('/[a-z]/i');
    $initials = ???
    echo $initials('This is rather cool :)'); // T I R C
    Building things #2

    View Slide

  111. $explode = curry('explode');
    $implode = curry('implode');
    $match = curry('preg_match');
    $head = function ($s) { return $s[0]; };
    $isWord = $match('/[a-z]/i');
    $initials = $compose([
    $implode(' '),
    $map('strtoupper'),
    $map($head),
    $filter($isWord),
    $explode(' ')
    ]);
    echo $initials('This is rather cool :)'); // T I R C
    Building things #2

    View Slide

  112. Building things #2
    $explode = curry('explode');
    $implode = curry('implode');
    $match = curry('preg_match');
    $head = function ($s) { return $s[0]; };
    $isWord = $match('/[a-z]/i');
    $initials = $compose([
    $implode(' '),
    $map($o('strtoupper')($head)),
    $filter($isWord),
    $explode(' ')
    ]);
    echo $initials('This is rather cool :)'); // T I R C
    Optimisation for free

    View Slide

  113. // Imperative
    function initials($sentence) {
    $res = '';
    $bits = explode(' ', $sentence);
    foreach ($bits as $bit) {
    if (preg_match('/[a-z]/i', $bit)) {
    $res .= strtoupper($bit[0]).' ';
    }
    }
    return trim($res);
    }
    // Functional
    $initials = $compose([
    $implode(' '),
    $map($o('strtoupper')($head)),
    $filter($isWord),
    $explode(' ')
    ]);
    Imperative vs Functional

    View Slide

  114. How is any of this
    relevant for a practicing
    programmer in 2017?

    View Slide

  115. • Absence of mutable state makes reasoning simple
    • Testing is trivial with pure functions
    • Focus on data and how it flows helps understanding
    • Composition is a great way to manage complexity
    • Computation vs effects: functional core/imperative shell
    Non-exhaustive pros list
    Non-exhaustive cons list
    • Requires a different mindset
    • More difficult to reason about performance

    View Slide

  116. Questions?
    https://github.com/pwm/fp-php-talk
    (The code from the slides to play with)

    View Slide