Programação Funcional em PHP: saia da zona de conforto

Programação Funcional em PHP: saia da zona de conforto

Não existe solução única para todos os problemas em tecnologia. O mesmo acontece para linguagens de programação! Aprenderemos mais sobre elas através do paradigma de programação funcional. Abordaremos paradigmas de programação, programação funcional e conceitos relacionados (funções de primeira classe, alta ordem e puras, estados, imutabilidade e recursão), programação funcional em PHP, map, filter e reduce, funções parciais, memoization e currying, composição, bibliotecas em PHP, vantagens e desvantagens.

52711e2157a6fed933b0361cc06a6953?s=128

Marcel dos Santos

September 21, 2019
Tweet

Transcript

  1. Programação Funcional em PHP saia da zona de conforto Marcel

    Gonçalves dos Santos @marcelgsantos λ
  2. pensandonaweb.com.br desenvolvedor web full-stack Marcel Gonçalves dos Santos @marcelgsantos

  3. None
  4. @femugsp sp.femug.com

  5. @phpsp phpsp.org.br

  6. Learning OOP in PHP Tutoriais, vídeos, slides, livros sobre OOP,

    OOD, design patterns, refatoração e arquitetura. bit.ly/Learning-OOP-in-PHP
  7. Interaja nas mídias sociais!
 
 - fale sobre o evento,

    palestrantes e conteúdo - tire fotos do evento e publique
 - interaja com outros participantes do evento - tire dúvidas ou dê feedbacks para os palestrantes
  8. 1. seguir @marcelgsantos no Twitter
 2. tuitar utilizando as hashtags

    #phpmgconf,
 #funcional e #php
 3. não vale tuíte em branco e retuíte
 4. ler e preencher este simples formulário
 bit.ly/sorteio-phpmg Concorra a um livro da Casa do Código!
  9. O que é programação funcional?

  10. é um paradigma de programação que utiliza funções puras e

    foca na transformação do estado
  11. O que é paradigma de programação?

  12. são modelos ou estilos de programação suportados por linguagens que

    agrupam certas características comuns
  13. Os paradigmas de programação definem como os códigos são estruturados.

  14. principais paradigmas de programação
 os dois principais paradigmas são o

    imperativo e o declarativo
  15. paradigma imperativo
 descreve a resolução de um problema através de

    comandos que o computador pode compreender e executar
  16. paradigma imperativo
 os paradigmas procedural e orientado a objetos são

    exemplos de paradigmas imperativos
  17. !// Imperative code to sum 1 to 10
 $sum =

    0; for ($i = 1; $i !<= 10; $i!++) { $sum += $i; } print $sum; !// 55
  18. paradigma declarativo
 permite especificar o que deve ser computado e

    não como deve ser computado
  19. paradigma declarativo
 os paradigmas funcional e lógico são exemplos de

    paradigmas declarativos
  20. !// Declarative code to sum 1 to 10 print array_sum(range(1,

    10)); !// 55
  21. paradigmas de linguagens de programação
 
 imperativo
 procedural - C

    e Pascal orientado a objetos - C++, Java, JavaScript, PHP, Python e Ruby
 
 declarativo
 lógico - Prolog funcional - Clojure, Elixir, Elm, Erlang, F#, Haskell, Lisp, OCaml e Scala
  22. Programação
 Funcional λ

  23. paradigma de programação que utiliza funções puras e foca na

    transformação do estado
  24. baseado no cálculo lambda proposto por Alonzo Church na década

    de 30
  25. na programação funcional as funções são tratadas como conceito principal

  26. Uma função matemática trata-se de um simples mapeamento entre o

    domínio e o contra-domínio. 1 2 3 D B A C X Y
  27. Estado λ

  28. o estado de um programa é representado pelos valores dos

    dados armazenados na memória…
  29. …em qualquer ponto de execução do programa

  30. o estado de uma aplicação é alterado a cada interação

    feita pelo usuário ou pelo próprio sistema…
  31. …e pode ser representado por uma estrutura de dados

  32. a maioria dos bugs são relacionados ao controle de estado

  33. Funções Puras λ

  34. funções puras
 
 1. ter parâmetros de entrada 
 2.

    não depender do estado externo 
 3. retorno baseado nos valores de entrada 
 4. não devem causar efeitos colaterais
  35. !// pure or impure function? $counter = 0; $increment =

    function () use (&$counter) { $counter!++; return $counter; }; print $increment(); !// 1
  36. !// pure function function add($x, $y) { return $x +

    $y; } print add(2, 3); !// 5
  37. !// pure function using closure syntax $add = function ($x,

    $y) { return $x + $y; }; print $add(2, 3); !// 5
  38. !// pure function using arrow function
 !// syntax (PHP 7.4)

    $add = fn($x, $y) !=> $x + $y; print $add(2, 3); !// 5
  39. por que utilizar funções puras?
 são reutilizáveis, componíveis, fáceis de

    testar, fáceis de cachear e paralelizáveis
  40. transparência referencial
 propriedade que garante que a saída de uma

    função pura sempre será a mesma dado um mesmo conjunto de argumentos
  41. !// referential transparency $add = fn($x, $y) !=> $x +

    $y; var_dump($add(2, 3) !!=== 5); !// true var_dump(5 !!=== 5); !// true
  42. pode não ser fácil criar funções puras

  43. porém, a restritividade ajuda a melhorar o foco

  44. Mais sobre
 Funções λ

  45. funções de primeira classe
 são funções que podem ser tratadas

    como valores, ou seja, podem ser atribuídas a variáveis, passadas como argumentos e retornadas de uma função
  46. !// first-class function $add = fn($x, $y) !=> $x +

    $y; $numbers = [1, 2, 3, 4, 5]; $sum = array_reduce($numbers, $add); $sum10 = array_reduce($numbers, $add, 10); print $sum; !// 15 print $sum10; !// 25
  47. !// first-class function $add = fn($x, $y) !=> $x +

    $y; $numbers = [1, 2, 3, 4, 5]; $sum = array_reduce($numbers, $add); $sum10 = array_reduce($numbers, $add, 10); print $sum; !// 15 print $sum10; !// 25
  48. funções de alta ordem
 são funções que operam sobre outras

    funções
  49. !// high-order function $add = fn($x, $y) !=> $x +

    $y; $numbers = [1, 2, 3, 4, 5]; $sum = array_reduce($numbers, $add); $sum10 = array_reduce($numbers, $add, 10); print $sum; !// 15 print $sum10; !// 25
  50. !// high-order function $add = fn($x, $y) !=> $x +

    $y; $numbers = [1, 2, 3, 4, 5]; $sum = array_reduce($numbers, $add); $sum10 = array_reduce($numbers, $add, 10); print $sum; !// 15 print $sum10; !// 25
  51. Os conceitos de funções de primeira classe e funções de

    alta ordem estão intimamente relacionados, uma não existiria sem a outra.
  52. funções anônimas
 funções que não possuem nome e que, geralmente,

    são passadas como argumento ou atribuídas
  53. !// anonymous function $numbers = [1, 2, 3, 4, 5];

    $sum = array_reduce($numbers, fn($x, $y) !=> $x + $y); print $sum; !// 15
  54. escopo
 uma função lambda ou função anônima tem o seu

    próprio escopo como qualquer função no PHP
  55. escopo
 o escopo é tratado de forma diferente entre as

    linguagens JavaScript e PHP
  56. escopo
 no JavaScript uma função anônima pode acessar uma variável

    do escopo externo enquanto no PHP isto não é permitido
  57. closures
 funções que possuem acesso à valores do escopo externo

  58. !// closure function function greet($greeting) { return function ($name) use

    ($greeting) { return "$greeting $name!"; }; } $greet = fn($greeting) !=> fn($name) !=> "$greeting $name!"; print greet('Hello')('Mary'); !// Hello Mary! print $greet('Hello')('Mary'); !// Hello Mary!
  59. closures
 as closures em PHP utilizam a abordagem early-binding, ou

    seja, as variáveis da closure terão os valores que tinham quando a closure foi definida
  60. closures
 isso pode ser sobrescrito utilizando passagem por referência ou

    redefinindo uma closure
  61. funções como objetos
 no PHP as funções são consideradas objetos

  62. !// function as object class Hello { public function !__invoke($name)

    { return "Hello $name!"; } } $hello = new Hello; print $hello('John'); !// Hello John! a classe deve implementar o método __invoke
  63. recursão
 é quando uma função é definida em termos de

    si própria, ou seja, quando a função chama ela mesma
  64. !// recursive function function factorial($number) { if ($number !!=== 1)

    { return 1; } else { return ($number * factorial($number - 1)); } } print factorial(5); !// 120
  65. !// recursive function (using closure syntax) $factorial = function ($number)

    use (&$factorial) { if ($number !!=== 1) { return 1; } else { return ($number * $factorial($number - 1)); } }; print $factorial(5); !// 120
  66. diferença entre função e procedimento (procedure)
 uma função recebe um

    valor e retorna um resultado; um procedimento é um conjunto de comandos executados numa ordem
  67. “Don't think of functions as a collection of instructions. Think

    of them as non-destructive operations on input `double = n => n * 2;`” Eric Elliott, 2016. https:/ /twitter.com/_ericelliott/status/685172918784004097
  68. memoize
 técnica que permite que funções custosas sejam cacheadas para

    execuções posteriores mais rápidas
  69. !// expensive cost function memoized $factorial = $memoize(function ($number) use

    (&$factorial) { sleep(1); !// it takes 1s to run! if ($number !!=== 1) { return 1; } else { return ($number * $factorial($number - 1)); } }); print $factorial(5); !// 120 (after 5s) print $factorial(7); !// 5040 (after 2s)
  70. Imutabilidade λ

  71. a imutabilidade diz que um dado não pode ser alterado

    após a sua criação
  72. a imutabilidade permite maior confiança e evita que erros ocorram

  73. o PHP não possui suporte completo a dados imutáveis de

    forma nativa
  74. porém, algumas técnicas como value objects podem ser utilizadas para

    alcançar a imutabilidade
  75. Currying e
 Aplicação Parcial λ

  76. o currying é a técnica que permite transformar uma função

    que recebe múltiplos argumentos…
  77. …em uma função que recebe apenas um argumento e que

    retorna uma função que aceita os argumentos restantes
  78. !// uncurried function
 function greet($greeting, $name) { return "$greeting $name";

    } print greet('Good morning', 'Alice'); !// Good morning Alice $greetMorning = greet('Good morning'); !// PHP Fatal error: Uncaught ArgumentCountError: Too !// few arguments to function greet(), 1 passed
  79. !// "curried" function function greet($greeting) { return function ($name) use

    ($greeting) { return "$greeting $name"; }; } $greetMorning = greet('Good morning'); print $greetMorning('Alice'); !// Good morning Alice print greet('Good morning')('Alice'); !// Good morning Alice print greet('Good morning', 'Alice'); !// error!
  80. !// "curried" function using arrow function (PHP 7.4) $greet =

    fn($greeting) !=> fn($name) !=> "$greeting $name!"; $greetMorning = $greet('Good morning'); print $greetMorning('Alice'); !// Good morning Alice print $greet('Good morning')('Alice'); !// Good morning Alice print $greet('Good morning', 'Alice'); !// error!
  81. !// curried function using Functional library $greet = curry(function ($greeting,

    $name) { return "$greeting $name"; }); print $greet('Good morning')('Alice'); !// Good morning Alice print $greet('Good morning', 'Alice'); !// Good morning Alice
  82. a aplicação parcial é quando se executa uma função e

    passa apenas parte de seus argumentos
  83. !// using a helper function that allows to perform !//

    partial application in a regular not curried function $add = function ($x, $y) { return $x + $y; }; $add3 = partial($add, 3); print $add3(2); !// 5
  84. a aplicação parcial permite fazer a especialização de uma função

    mais genérica
  85. !// specialization from a curried function !// using partial application

    $greet = curry(function ($greeting, $name) { return "$greeting $name"; });
 $greetMorning = $greet('Good morning'); print $greetMorning('Alice'); !// Good morning Alice
  86. !// specialization from a curried function !// using partial application

    (PHP 7.4) $greet = curry(fn($greeting, $name) !=> "$greeting $name"); 
 $greetMorning = $greet('Good morning'); print $greetMorning('Alice'); !// Good morning Alice
  87. currying e aplicação parcial são recursos muito utilizados em programação

    funcional
  88. na programação funcional deve-se levar em consideração a ordem dos

    parâmetros
  89. os parâmetros mais genéricos devem vir mais para o início

    e os parâmetros mais específicos devem vir mais para o final
  90. o PHP não possui suporte nativo para currying como nas

    linguagens puramente funcionais Elm ou Haskell
  91. Composição
 de Funções λ

  92. a composição é o processo de combinar uma ou mais

    funções para criar uma nova função
  93. !// create a function using composition (traditional way) $sentence =

    'estava à toa na vida o meu amor me chamou pra ver a banda passar cantando coisas de amor';
 $wordCount = function ($text) { return count(explode(' ', $text)); }; print $wordCount($sentence); !// 19
  94. é uma solução elegante e legível e ajuda a evitar

    a utilização do aninhamento de funções
  95. a biblioteca Functional possui uma função que permite criar uma

    nova função a partir da composição de funções
  96. !// create a function using composition $sentence = 'estava à

    toa na vida o meu amor me chamou pra ver a banda passar cantando coisas de amor'; $wordCount = compose(partial('explode', ' '), 'count'); print $wordCount($sentence); !// 19
  97. Diferenças 
 entre OO e FP λ

  98. um objeto possui características, comportamentos e estado atual e realiza

    operações sobre o seu próprio estado
  99. uma função não faz alterações diretas no estado e, sim,

    retorna novas transformações do estado atual
  100. Caso de 
 Uso λ

  101. Caso de Uso 1
 somar os preços dos produtos de

    um carrinho de compra
  102. !// shopping cart $cart = [ ['id' !=> 1, 'product'

    !=> 'iPhone', 'price' !=> 499], ['id' !=> 2, 'product' !=> 'Kindle', 'price' !=> 179], ['id' !=> 3, 'product' !=> 'MacBook Pro', 'price' !=> 1199], ]; $total = 0; !// get price from shopping cart and sum them !// imperative way (using for-loop and accumulator) for ($i = 0; $i < count($cart); $i!++) { $total += $cart[$i]['price']; } print $total; !// 1877 Passo 1
  103. !// shopping cart $cart = [ ['id' !=> 1, 'product'

    !=> 'iPhone', 'price' !=> 499], ['id' !=> 2, 'product' !=> 'Kindle', 'price' !=> 179], ['id' !=> 3, 'product' !=> 'MacBook Pro', 'price' !=> 1199], ]; !// get prices from shopping cart and sum them !// functional way (intermediate values) $cartPrices = map(fn($item) !=> $item['price'], $cart); $total = sum($cartPrices); print $total; !// 1877 Passo 2 realiza o mapeamento da lista de produtos (objetos) para uma lista de preços (números) faz a somatória da lista de números e retorna o total
  104. !// shopping cart $cart = [ ['id' !=> 1, 'product'

    !=> 'iPhone', 'price' !=> 499], ['id' !=> 2, 'product' !=> 'Kindle', 'price' !=> 179], ['id' !=> 3, 'product' !=> 'MacBook Pro', 'price' !=> 1199], ]; !// get prices from shopping cart and sum them !// functional way (functional composition) $totalCart = compose( map(fn($item) !=> $item['price']), 'f\sum' ); print $totalCart($cart); !// 1877 Passo 3 cria uma nova função a partir da composição de funções e elimina valores intermediários aplicação parcial da função map
  105. Outras
 Bibliotecas λ

  106. bibliotecas
 
 1. lstrojny/functional-php
 2. kapolos/pramda
 3. sergiors/prelude
 4. widmogrod/php-functional


    5. nikic/iter
 6. leocavalcante/siler
 7. ihor/Nspl " "
  107. Conclusão λ

  108. as linguagens de programação tradicionais têm adotado conceitos de programação

    funcional logo é importante conhecê-los
  109. por mais que o PHP não tenha um suporte amplo

    a programação funcional o mindset funcional te ajudará a se tornar um(a) programador(a) melhor
  110. a programação funcional não é sobre não ter estado…

  111. …e sim sobre eliminar estado e efeito colateral sempre que

    possível e controlar efeitos colaterais quando necessário
  112. foque na transformação do estado e evite efeitos colaterais

  113. conhecer bem os paradigmas de programação te permite escolher a

    melhor ferramenta para cada problema
  114. A programação funcional garante o que é código bom em

    outros paradigmas.
  115. existem inúmeros conceitos relacionados a programação funcional como functors, monads,

    lazy evaluation, tail call optimization…
  116. vá em frente e divirta-se!

  117. Referências

  118. Getting Started with FP in PHP Tutoriais, vídeos, slides, bibliotecas,

    pessoas influentes sobre programação funcional em PHP. bit.ly/Getting-Started-with-FP-in-PHP
  119. Avalie!

  120. bit.ly/avalie-palestra-php-funcional

  121. Anúncio!

  122. bit.ly/workshop-php74 Informações: será apresentado um histórico breve da linguagem, as

    principais funcionalidades do PHP 7.4 de forma prática como typed properties, arrow functions, spread operator, preloading, FFI entre outras e funcionalidades futuras do PHP 8.0.
  123. @marcelgsantos speakerdeck.com/marcelgsantos Obrigado. Perguntas?