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

O Essencial da Programação Funcional em Elixir 1.1

O Essencial da Programação Funcional em Elixir 1.1

Versão Elixir Brasil

O mundo está caminhando cada vez mais para o paradigma funcional. Lançamento de linguagens de programação acontece frequentemente, porém adoção de um novo paradigma é algo mais raro. Precisamos entender essa mudança para estar preparado para o desenvolvimento de novos softwares da próximas décadas. Sou desenvolvedor há 9 anos que embarcou no paradigma funcional recentemente e autor no livro "Learn Functional Programming with Elixir" pela Pragmatic Programmers.

Nesta talk você vai aprender o porque a programação funcional importa para as demandas modernas. Iremos explorar os três conceitos essenciais de programação funcional em Elixir: imutabilidade, código declarativo e funções puras.

Esta é uma talk para iniciantes em programação funcional. Iremos discutir como é importante criar programas que sejam altamente paralelizáveis para os hardwares atuais. Será discutido como os conceitos de programação funcional suprem essas demandas de maneira melhor do que as linguagens convencionais.

50e713934ed341675bf1fa73127ec260?s=128

Ulisses Almeida

October 28, 2017
Tweet

Transcript

  1. O Essencial da Programação Funcional em Elixir

  2. 3 conceitos essenciais

  3. ⏹ Funções ⏹ Código declarativo ⏹ Imutabilidade

  4. Me

  5. @ulissesalmeida

  6. @ulissesalmeida

  7. None
  8. None
  9. None
  10. Não estamos contratando !

  11. Banco de Talentos Elixir / Ruby

  12. http:// careers.plataformatec.co m.br/

  13. None
  14. None
  15. None
  16. 20% de desconto Elixir Brasil

  17. Agora chega vamos voltar pra talk XD

  18. None
  19. Por que se preocupar com paralelismo?

  20. None
  21. None
  22. None
  23. None
  24. Múltiplos núcleos ! Paralelismo

  25. Your Erlang program should just run N times faster on

    an N core processor https://pragprog.com/articles/erlang
  26. None
  27. Básico Programa que não roda em paralelo Roda 0 vezes

    mais rápido com 2 ou mais cores
  28. None
  29. 50% paralelizável 2 vezes mais rápido

  30. None
  31. 75% paralelizável ~3 vezes mais rápido

  32. None
  33. 90% paralelizável ~6 vezes mais rápido

  34. None
  35. 95% paralelizável ~9 vezes mais rápido

  36. Quanto mais partes do programa em paralelo melhor!?

  37. None
  38. O código sozinho não roda em paralelo

  39. !

  40. Threads

  41. None
  42. None
  43. Precisa reduzir a complexidade

  44. None
  45. Programação Funcional ❤ Paralelismo

  46. ⏹ Funções ⏹ Código declarativo ⏹ Imutabilidade

  47. Funções puras

  48. Escopo { Argumento } Argumento => Resultado Valores imutáveis

  49. add2 = fn (n) -> n + 2 end add2.(2)

    # => 4
  50. Valores sempre são explícitos

  51. Ruby

  52. class MySet attr_reader :items def initialize @items = [] end

    def push(item) items.push(item) unless items.include?(item) end end
  53. set = MySet.new set.push("apple") new_set = MySet.new new_set.push("pie") set.push("apple") #

    => ["apple"] new_set.push("apple") # => ["pie", "apple"]
  54. class Order attr_reader :user, :products, :logger, :mailer, :payment, :source #...

    end
  55. Elixir

  56. defmodule MySet do defstruct items: [] def push(set = %{items:

    items}, item) do if Enum.member?(items, item) do set else %{set | items: items ++ [item]} end end end
  57. set = %MySet{} set = MySet.push(set, "apple") new_set = %MySet{}

    new_set = MySet.push(new_set, "pie") IO.inspect MySet.push(set, "apple") # => ["apple"] IO.inspect MySet.push(new_set, "apple") # => ["pie", "apple"]
  58. Funções como valores

  59. Enum.map( ["dogs", "cats", "flowers"], &String.upcase/1 ) # => ["DOGS", "CATS",

    "FLOWERS"]
  60. Transformação de valores

  61. capitalize_words("the dark tower") # => "The Dark Tower"

  62. def capitalize_words(title) do join_with_whitespace( capitalize_all( String.split(title) ) ) end

  63. def capitalize_words(title) do title |> String.split |> capitalize_all |> join_with_whitespace

    end
  64. ✅ Funções ⏹ Código declarativo ⏹ Imutabilidade

  65. None
  66. Código imperativo Foco no como

  67. Javascript

  68. function capitalizeAll(list) { var newList = []; for (var i

    = 0; i < list.length; i++) { newList.push(capitalize(list[i])); } return newList; } function capitalize(string) { return string.charAt(0).toUpperCase() + string.slice(1); }
  69. var list = ["dogs", "hot dogs", "bananas"]; capitalizeAll(list); // =>

    ["Dogs", "Hot dogs", "Bananas"]
  70. Código declarativo Foco no o quê

  71. Elixir

  72. defmodule StringList do def capitalize_all([]), do: [] def capitalize_all([first |

    rest]) do [String.capitalize(first) | capitalize_all(rest)] end end
  73. list = ["dogs", "hot dogs", "bananas"] Enum.map(list, &String.capitalize/1) # =>

    ["Dogs", "Hot Dogs", "Bananas"]
  74. Javascript

  75. list = ["dogs", "hot dogs", "bananas"] list.map((i) => i.toUpperCase()); //

    => ["DOGS", "HOT DOGS", "BANANAS"]
  76. Ruby

  77. list = ["dogs", "hot dogs", "bananas"] list.map(&:upcase) # => ["DOGS",

    "HOT DOGS", "BANANAS"]
  78. ✅ Funções ✅ Código declarativo ⏹ Imutabilidade

  79. Ruby

  80. list = [1, 2, 3, 4] list.pop puts list.inspect #

    => [1, 2, 3] list.push(1) puts list.inspect # => [1, 2, 3, 1]
  81. None
  82. Account = Struct.new(:amount) do def deposit(value) new_amount = amount +

    value sleep(1) self.amount = new_amount end def withdraw(value) new_amount = amount - value sleep(1) self.amount = new_amount end end
  83. ilisses = Account.new(100) ilisses.deposit(20) ilisses.withdraw(20) ilisses.amount # 100

  84. ilisses = Account.new(100) Thread.new { ilisses.deposit(20) } Thread.new { ilisses.withdraw(20)

    }
  85. ilisses = Account.new(100) 5.times.map { Thread.new { ilisses.deposit(20) } }

    + 5.times.map { Thread.new { ilisses.withdraw(20) } }
  86. ilisses = Account.new(100) threads = 5.times.map { Thread.new { ilisses.deposit(20)

    } } + 5.times.map { Thread.new { ilisses.withdraw(20) } } threads.each(&:join) puts ilisses.amount
  87. ilisses = Account.new(100) 5.times { threads = 5.times.map { Thread.new

    { ilisses.deposit(20) } } + 5.times.map { Thread.new { ilisses.withdraw(20) } } threads.each(&:join) puts ilisses.amount ilisses = Account.new(100) }
  88. 120 80 100 80 120

  89. Elixir

  90. list = [1, 2, 3] List.delete_at(list, -1) list ++ [4]

    IO.inspect(list) # => [1, 2, 3]
  91. None
  92. list = [1, 2, 3] # A ordem não importa

    List.delete_at(list, -1) list ++ [4] IO.inspect(list) # => [1, 2, 3]
  93. list = [1, 2, 3] # A ordem importa list

    = List.delete_at(list, -1) list = list ++ [4] IO.inspect(list) # => [1, 2, 4]
  94. Se eu quiser compartilhar valores?

  95. {:ok, ulice_account} = Agent.start_link(fn -> 100 end) deposit_20 = fn

    -> Agent.update(ulice_account, fn amount -> Process.sleep(100) amount + 20 end) end withdraw_20 = fn -> Agent.update(ulice_account, fn amount -> Process.sleep(100) amount - 20 end) end
  96. deposit_20.() withdraw_20.() IO.inspect Agent.get(ulice_account, fn amount -> amount end) #

    100
  97. Task.async(deposit_20) Task.async(withdraw_20)

  98. for _i <- 1..5, do: Task.async(deposit_20) for _i <- 1..5,

    do: Task.async(withdraw_20)
  99. deposits = for _i <- 1..5, do: Task.async(deposit_20) withdraws =

    for _i <- 1..5, do: Task.async(withdraw_20) Enum.each(deposits ++ withdraws, &(Task.await/1)) IO.inspect Agent.get(ulice_account, fn amount -> amount end)
  100. for _i <- 1..5 do deposits = for _i <-

    1..5, do: Task.async(deposit_20) withdraws = for _i <- 1..5, do: Task.async(withdraw_20) Enum.each(deposits ++ withdraws, &(Task.await/1)) IO.inspect Agent.get(ulice_account, fn amount -> amount end) end Agent.stop(ulice_account)
  101. 100 100 100 100 100

  102. Imutabilidade no Ruby?

  103. User = Struct.new(:name) list = [User.new("Bob"), User.new("Anna")] list.freeze list.push(User.new("July")) #

    => RuntimeError: can't modify frozen Array list[0].name = "Ted" puts list.inspect # => [#<struct User name="Ted">, # <struct User name="Anna">]
  104. Compartilhar valor no Ruby?

  105. https://github.com/ruby- concurrency/concurrent- ruby

  106. None
  107. None
  108. ✅ Imutabilidade ✅ Funções ✅ Código declarativo

  109. None
  110. Obrigado!