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 full-size slide

  2. What is
    Functional Programming?

    View full-size slide

  3. Functional Programming is
    programming with functions.

    View full-size slide

  4. What is a function?

    View full-size slide

  5. Marc
    Claire
    Adam
    Nora
    Coffee
    Tea
    A B

    View full-size slide

  6. Marc
    Claire
    Adam
    Nora
    Coffee
    Tea
    A B

    View full-size slide

  7. Marc
    Claire
    Adam
    Nora
    Coffee
    Tea
    A B

    View full-size slide

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

    View full-size slide

  9. Functions in code

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  14. // 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 full-size slide

  15. // 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 full-size slide

  16. 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 full-size slide

  17. // 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 full-size slide

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

    View full-size slide

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

    View full-size slide

  20. 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 full-size slide

  21. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

  24. 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 full-size slide

  25. 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 full-size slide

  26. 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 full-size slide

  27. You have just witnessed
    Higher-order functions

    View full-size slide

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

    View full-size slide

  29. Alonzo Church

    View full-size slide

  30. 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 full-size slide

  31. 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 full-size slide

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

    View full-size slide

  33. Functions as building
    blocks

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  36. 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 full-size slide

  37. 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 full-size slide

  38. This is called
    composition

    View full-size slide

  39. Composition in code

    View full-size slide

  40. $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 full-size slide

  41. Huh, but where is ?
    g f

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  44. 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 full-size slide

  45. 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 full-size slide

  46. Closure
    an important
    implementation detail

    View full-size slide

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

    View full-size slide

  48. $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 full-size slide

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

    View full-size slide

  50. 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 full-size slide

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

    View full-size slide

  52. 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 full-size slide

  53. Fixing little circle…

    View full-size slide

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

    View full-size slide

  55. 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 full-size slide

  56. What about composing
    functions with multiple
    arguments?

    View full-size slide

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

    View full-size slide

  58. 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 full-size slide

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

    View full-size slide

  60. This is called
    currying

    View full-size slide

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

    View full-size slide

  62. 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 full-size slide

  63. Currying also means
    injecting behaviour

    View full-size slide

  64. 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 full-size slide

  65. Now we can compose
    functions with any arity!

    View full-size slide

  66. 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 full-size slide

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

    View full-size slide

  68. =
    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 full-size slide

  69. 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 full-size slide

  70. Currying is tedious, we
    need some syntactic sugar

    View full-size slide

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

    View full-size slide

  72. 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 full-size slide

  73. Composition has
    interesting properties

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  77. 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 full-size slide

  78. $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 full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  84. 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 full-size slide

  85. $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 full-size slide

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

    View full-size slide

  87. 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 full-size slide

  88. 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 full-size slide

  89. 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 full-size slide

  90. Fold is the essence of
    recursion.

    View full-size slide

  91. 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 full-size slide

  92. 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 full-size slide

  93. 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 full-size slide

  94. What about composing
    a list of functions?

    View full-size slide

  95. $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 full-size slide

  96. $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 full-size slide

  97. $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 full-size slide

  98. Building things

    View full-size slide

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

    View full-size slide

  100. $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 full-size slide

  101. $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 full-size slide

  102. $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 full-size slide

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

    View full-size slide

  104. $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 full-size slide

  105. $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 full-size slide

  106. 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 full-size slide

  107. // 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 full-size slide

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

    View full-size slide

  109. • 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 full-size slide

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

    View full-size slide