Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Problemas que o Elm resolve
só com o compilador
sem nada mais
@cuducos
cuducos.me
1 / 73
2 / 73
3 / 73
4 / 73
5 / 73
6 / 73
“O melhor caso de uso de Haskell”
— Felipe de Morais
7 / 73
$ elm-make Main.elm  --warn
8 / 73
Propriedades que podem não existir
1
9 / 73
user = {
name: 'Eduardo Cuducos',
twitter: 'cuducos'
}
const getSocialMedia = (user) => user.facebook
getSocialMedia(user)...
user = {
name: 'Eduardo Cuducos',
twitter: 'cuducos'
}
const getSocialMedia = (user) => user.facebook
getSocialMedia(user)...
class User:
def __init__(self, name, twitter):
self.name = name
self.twitter = twitter
user = User('Eduardo Cuducos', 'cud...
class User:
def __init__(self, name, twitter):
self.name = name
self.twitter = twitter
user = User('Eduardo Cuducos', 'cud...
type alias User =
{ name : String
, twitter : String
}
getSocialMedia : User -> String
getSocialMedia user =
user.facebook...
type alias User =
{ name : String
, twitter : String
}
getSocialMedia : User -> String
getSocialMedia user =
user.facebook...
type alias User =
{ name : String
, twitter : String
}
getSocialMedia : User -> String
getSocialMedia user =
user.twitter
...
type alias User =
{ name : String
, twitter : String
}
getSocialMedia : User -> String
getSocialMedia user =
user.twitter
...
Elm não te deixa com
o undefined na mão!
18 / 73
Objetos que podem não existir
2
19 / 73
users = [
{ name: 'Eduardo Cuducos', twitter: 'cuducos' },
{ name: 'Hugo Bessa', twitter: 'hugobessaa' }
]
const firstUser...
users = [
{ name: 'Eduardo Cuducos', twitter: 'cuducos' },
{ name: 'Hugo Bessa', twitter: 'hugobessaa' }
]
const firstUser...
users = []
firstUserName(users)
22 / 73
users = []
firstUserName(users)
TypeError: Cannot read property 'name' of undefined
23 / 73
users = [
User('Eduardo Cuducos', 'cuducos'),
User('Hugo Bessa', 'hugobessaa')
]
def first_user_name(users):
return users[...
users = [
User('Eduardo Cuducos', 'cuducos'),
User('Hugo Bessa', 'hugobessaa')
]
def first_user_name(users):
return users[...
users = []
first_user_name(users)
26 / 73
users = []
first_user_name(users)
IndexError: list index out of range
27 / 73
users = []
first_user_name(users)
IndexError: list index out of range
def first_user_name(users):
first_user, *_ = users
r...
users = []
first_user_name(users)
IndexError: list index out of range
def first_user_name(users):
first_user, *_ = users
r...
firstUserName : List User -> String
firstUserName users =
let
firstUser = List.head users
in
firstUser.name
30 / 73
firstUserName : List User -> String
firstUserName users =
let
firstUser = List.head users
in
firstUser.name
-- TYPE MISMAT...
firstUserName : List User -> String
firstUserName users =
case List.head users of
Just user ->
user.name
Nothing ->
"User ...
firstUserName : List User -> String
firstUserName users =
case List.head users of
Just user ->
user.name
Nothing ->
"User ...
Elm te obri a a preparar a
aplicação para casos raros, extremos!
34 / 73
Missão impossível
3
35 / 73
const tomorrow = (today) => parseInt(today) + 1
tomorrow('18')
36 / 73
const tomorrow = (today) => parseInt(today) + 1
tomorrow('18')
19
37 / 73
tomorrow(undefined)
38 / 73
tomorrow(undefined)
NaN
39 / 73
def tomorrow(today):
return int(today) + 1
tomorrow('18')
40 / 73
def tomorrow(today):
return int(today) + 1
tomorrow('18')
19
41 / 73
tomorrow(None)
42 / 73
tomorrow(None)
TypeError: int() argument must be a string, a bytes-like object or a number, not 'NoneType'
43 / 73
tomorrow(None)
TypeError: int() argument must be a string, a bytes-like object or a number, not 'NoneType'
tomorrow('NaN')...
tomorrow(None)
TypeError: int() argument must be a string, a bytes-like object or a number, not 'NoneType'
tomorrow('NaN')...
tomorrow : String -> Int
tomorrow today =
(String.toInt today) + 1
46 / 73
tomorrow : String -> Int
tomorrow today =
(String.toInt today) + 1
-- TYPE MISMATCH --------------------------------------...
tomorrow : String -> Int
tomorrow today =
case String.toInt today of
Ok day ->
day + 1
Err _ ->
Debug.crash "TODO"
48 / 73
tomorrow : String -> Int
tomorrow today =
case String.toInt today of
Ok day ->
day + 1
Err _ ->
Debug.crash "TODO"
Success...
Elm te obri a a se antecipar a erros
em tempo de execução.
50 / 73
Mas e o Debug.crash?
51 / 73
view : String -> Html msg
view today =
case String.toInt today of
Ok day ->
viewMyApp
Err error ->
viewErroMsg error
52 / ...
Ações de usuário não previstas
4
53 / 73
‑ 41 +
54 / 73
const counter = (state, action) => {
switch (action.type) {
case 'INCREMENT':
return state + 1
case 'DECREMENT':
return st...
const counter = (state, action) => {
switch (action.type) {
case 'INCREMENT':
return state + 1
case 'DECREMENT':
return st...
const counter = (state, action) => {
switch (action.type) {
case 'INCREMENT':
return state + 1
case 'DECREMENT':
return st...
const counter = (state, action) => {
switch (action.type) {
case 'INCREMENT':
return state + 1
case 'DECREMENT':
return st...
‑ 21 + x2
59 / 73
const render = () => ReactDOM.render(
<p>
<button onClick={() => store.dispatch({ type: 'DECREMENT'})}>-</button>
{store.g...
const render = () => ReactDOM.render(
<p>
<button onClick={() => store.dispatch({ type: 'DECREMENT'})}>-</button>
{store.g...
const render = () => ReactDOM.render(
<p>
<button onClick={() => store.dispatch({ type: 'DECREMENT'})}>-</button>
{store.g...
type Msg = Increment | Decrement
update : Msg -> Int -> Int
update msg model =
case msg of
Increment -> model + 1
Decremen...
type Msg = Increment | Decrement
update : Msg -> Int -> Int
update msg model =
case msg of
Increment -> model + 1
Decremen...
view : Int -> Html Msg
view model =
p
[]
[ button [ onClick Increment ] [ text "+" ]
, text (toString model)
, button [ on...
view : Int -> Html Msg
view model =
p
[]
[ button [ onClick Increment ] [ text "+" ]
, text (toString model)
, button [ on...
type Msg = Increment | Decrement | Double
67 / 73
type Msg = Increment | Decrement | Double
-- MISSING PATTERNS --------------------------------------------------- Main.elm...
update : Msg -> Int -> Int
update msg model =
case msg of
Increment -> model + 1
Decrement -> model - 1
Double -> model * ...
update : Msg -> Int -> Int
update msg model =
case msg of
Increment -> model + 1
Decrement -> model - 1
Double -> model * ...
A arquitetura do Elm te dá arantia de que todas
as ações dos usuários estão previstas!
71 / 73
“Quem aprendeu al o novo hoje?”
— Raymond Hettin er
72 / 73
Muito obri ado : )
@cuducos
cuducos.me/blo
Vamos aprender Elm!
73 / 73
Upcoming SlideShare
Loading in …5
×

TDC2017 | São Paulo - Trilha Programação Funcional How we figured out we had a SRE team at - Problemas que o Elm resolve só com o compilador sem nada mais.

25 views

Published on

Trilha Programação Funcional How we figured out we had a SRE team at - Problemas que o Elm resolve só com o compilador sem nada mais.

Published in: Education
  • Be the first to comment

TDC2017 | São Paulo - Trilha Programação Funcional How we figured out we had a SRE team at - Problemas que o Elm resolve só com o compilador sem nada mais.

  1. 1. Problemas que o Elm resolve só com o compilador sem nada mais @cuducos cuducos.me 1 / 73
  2. 2. 2 / 73
  3. 3. 3 / 73
  4. 4. 4 / 73
  5. 5. 5 / 73
  6. 6. 6 / 73
  7. 7. “O melhor caso de uso de Haskell” — Felipe de Morais 7 / 73
  8. 8. $ elm-make Main.elm  --warn 8 / 73
  9. 9. Propriedades que podem não existir 1 9 / 73
  10. 10. user = { name: 'Eduardo Cuducos', twitter: 'cuducos' } const getSocialMedia = (user) => user.facebook getSocialMedia(user) 10 / 73
  11. 11. user = { name: 'Eduardo Cuducos', twitter: 'cuducos' } const getSocialMedia = (user) => user.facebook getSocialMedia(user) undefined 11 / 73
  12. 12. class User: def __init__(self, name, twitter): self.name = name self.twitter = twitter user = User('Eduardo Cuducos', 'cuducos') def get_social_media(user): return user.facebook get_social_media(user) 12 / 73
  13. 13. class User: def __init__(self, name, twitter): self.name = name self.twitter = twitter user = User('Eduardo Cuducos', 'cuducos') def get_social_media(user): return user.facebook get_social_media(user) AttributeError: 'User' object has no attribute 'facebook' 13 / 73
  14. 14. type alias User = { name : String , twitter : String } getSocialMedia : User -> String getSocialMedia user = user.facebook 14 / 73
  15. 15. type alias User = { name : String , twitter : String } getSocialMedia : User -> String getSocialMedia user = user.facebook -- TYPE MISMATCH ------------------------------------------------------ Main.elm `user` does not have a field named `facebook`. 15| user.facebook ^^^^^^^^^^^^^ The type of `user` is: User Which does not contain a field named `facebook`. Hint: The record fields do not match up. One has name and twitter. The other has facebook. 15 / 73
  16. 16. type alias User = { name : String , twitter : String } getSocialMedia : User -> String getSocialMedia user = user.twitter 16 / 73
  17. 17. type alias User = { name : String , twitter : String } getSocialMedia : User -> String getSocialMedia user = user.twitter Success! Compiled 1 module. 17 / 73
  18. 18. Elm não te deixa com o undefined na mão! 18 / 73
  19. 19. Objetos que podem não existir 2 19 / 73
  20. 20. users = [ { name: 'Eduardo Cuducos', twitter: 'cuducos' }, { name: 'Hugo Bessa', twitter: 'hugobessaa' } ] const firstUserName = (users) => users[0].name firstUserName(users) 20 / 73
  21. 21. users = [ { name: 'Eduardo Cuducos', twitter: 'cuducos' }, { name: 'Hugo Bessa', twitter: 'hugobessaa' } ] const firstUserName = (users) => users[0].name firstUserName(users) 'Eduardo Cuducos' 21 / 73
  22. 22. users = [] firstUserName(users) 22 / 73
  23. 23. users = [] firstUserName(users) TypeError: Cannot read property 'name' of undefined 23 / 73
  24. 24. users = [ User('Eduardo Cuducos', 'cuducos'), User('Hugo Bessa', 'hugobessaa') ] def first_user_name(users): return users[0].name first_user_name(users) 24 / 73
  25. 25. users = [ User('Eduardo Cuducos', 'cuducos'), User('Hugo Bessa', 'hugobessaa') ] def first_user_name(users): return users[0].name first_user_name(users) 'Eduardo Cuducos' 25 / 73
  26. 26. users = [] first_user_name(users) 26 / 73
  27. 27. users = [] first_user_name(users) IndexError: list index out of range 27 / 73
  28. 28. users = [] first_user_name(users) IndexError: list index out of range def first_user_name(users): first_user, *_ = users return first_use.name 28 / 73
  29. 29. users = [] first_user_name(users) IndexError: list index out of range def first_user_name(users): first_user, *_ = users return first_use.name ValueError: not enough values to unpack (expected at least 1, got 0) 29 / 73
  30. 30. firstUserName : List User -> String firstUserName users = let firstUser = List.head users in firstUser.name 30 / 73
  31. 31. firstUserName : List User -> String firstUserName users = let firstUser = List.head users in firstUser.name -- TYPE MISMATCH --------------------------------------------- Main.elm `firstUser` does not have a field named `name`. 29| firstUser.name ^^^^^^^^^^^^^^ The type of `firstUser` is: Maybe User Which does not contain a field named `name`. 31 / 73
  32. 32. firstUserName : List User -> String firstUserName users = case List.head users of Just user -> user.name Nothing -> "User not found" 32 / 73
  33. 33. firstUserName : List User -> String firstUserName users = case List.head users of Just user -> user.name Nothing -> "User not found" Success! Compiled 1 module. 33 / 73
  34. 34. Elm te obri a a preparar a aplicação para casos raros, extremos! 34 / 73
  35. 35. Missão impossível 3 35 / 73
  36. 36. const tomorrow = (today) => parseInt(today) + 1 tomorrow('18') 36 / 73
  37. 37. const tomorrow = (today) => parseInt(today) + 1 tomorrow('18') 19 37 / 73
  38. 38. tomorrow(undefined) 38 / 73
  39. 39. tomorrow(undefined) NaN 39 / 73
  40. 40. def tomorrow(today): return int(today) + 1 tomorrow('18') 40 / 73
  41. 41. def tomorrow(today): return int(today) + 1 tomorrow('18') 19 41 / 73
  42. 42. tomorrow(None) 42 / 73
  43. 43. tomorrow(None) TypeError: int() argument must be a string, a bytes-like object or a number, not 'NoneType' 43 / 73
  44. 44. tomorrow(None) TypeError: int() argument must be a string, a bytes-like object or a number, not 'NoneType' tomorrow('NaN') 44 / 73
  45. 45. tomorrow(None) TypeError: int() argument must be a string, a bytes-like object or a number, not 'NoneType' tomorrow('NaN') ValueError: invalid literal for int() with base 10: 'NaN' 45 / 73
  46. 46. tomorrow : String -> Int tomorrow today = (String.toInt today) + 1 46 / 73
  47. 47. tomorrow : String -> Int tomorrow today = (String.toInt today) + 1 -- TYPE MISMATCH ------------------------------------------------------ Main.elm The left argument of (+) is causing a type mismatch. 45| (String.toInt today) + 1 ^^^^^^^^^^^^^^^^^^ (+) is expecting the left argument to be a: number But the left argument is: Result String Int 47 / 73
  48. 48. tomorrow : String -> Int tomorrow today = case String.toInt today of Ok day -> day + 1 Err _ -> Debug.crash "TODO" 48 / 73
  49. 49. tomorrow : String -> Int tomorrow today = case String.toInt today of Ok day -> day + 1 Err _ -> Debug.crash "TODO" Success! Compiled 1 module. 49 / 73
  50. 50. Elm te obri a a se antecipar a erros em tempo de execução. 50 / 73
  51. 51. Mas e o Debug.crash? 51 / 73
  52. 52. view : String -> Html msg view today = case String.toInt today of Ok day -> viewMyApp Err error -> viewErroMsg error 52 / 73
  53. 53. Ações de usuário não previstas 4 53 / 73
  54. 54. ‑ 41 + 54 / 73
  55. 55. const counter = (state, action) => { switch (action.type) { case 'INCREMENT': return state + 1 case 'DECREMENT': return state - 1 } } 55 / 73
  56. 56. const counter = (state, action) => { switch (action.type) { case 'INCREMENT': return state + 1 case 'DECREMENT': return state - 1 } } const render = () => ReactDOM.render( <p> <button onClick={() => store.dispatch({ type: 'DECREMENT'})}>-</button> {store.getState()} <button onClick={() => store.dispatch({ type: 'INCREMENT'})}>+</button> </p> ) 56 / 73
  57. 57. const counter = (state, action) => { switch (action.type) { case 'INCREMENT': return state + 1 case 'DECREMENT': return state - 1 } } const render = () => ReactDOM.render( <p> <button onClick={() => store.dispatch({ type: 'DECREMENT'})}>-</button> {store.getState()} <button onClick={() => store.dispatch({ type: 'INCREMENT'})}>+</button> </p> ) + 57 / 73
  58. 58. const counter = (state, action) => { switch (action.type) { case 'INCREMENT': return state + 1 case 'DECREMENT': return state - 1 } } const render = () => ReactDOM.render( <p> <button onClick={() => store.dispatch({ type: 'DECREMENT'})}>-</button> {store.getState()} <button onClick={() => store.dispatch({ type: 'INCREMENT'})}>+</button> </p> ) + 42 58 / 73
  59. 59. ‑ 21 + x2 59 / 73
  60. 60. const render = () => ReactDOM.render( <p> <button onClick={() => store.dispatch({ type: 'DECREMENT'})}>-</button> {store.getSate()} <button onClick={() => store.dispatch({ type: 'INCREMENT'})}>+</button> <button onClick={() => store.dispatch({ type: 'DOUBLE'})}>x2</button> </p> ) 60 / 73
  61. 61. const render = () => ReactDOM.render( <p> <button onClick={() => store.dispatch({ type: 'DECREMENT'})}>-</button> {store.getSate()} <button onClick={() => store.dispatch({ type: 'INCREMENT'})}>+</button> <button onClick={() => store.dispatch({ type: 'DOUBLE'})}>x2</button> </p> ) x2 61 / 73
  62. 62. const render = () => ReactDOM.render( <p> <button onClick={() => store.dispatch({ type: 'DECREMENT'})}>-</button> {store.getSate()} <button onClick={() => store.dispatch({ type: 'INCREMENT'})}>+</button> <button onClick={() => store.dispatch({ type: 'DOUBLE'})}>x2</button> </p> ) x2 21 62 / 73
  63. 63. type Msg = Increment | Decrement update : Msg -> Int -> Int update msg model = case msg of Increment -> model + 1 Decrement -> model - 1 view : Int -> Html Msg view model = p [] [ button [ onClick Increment ] [ text "+" ] , text (toString model) , button [ onClick Decrement ] [ text "-" ] ] 63 / 73
  64. 64. type Msg = Increment | Decrement update : Msg -> Int -> Int update msg model = case msg of Increment -> model + 1 Decrement -> model - 1 view : Int -> Html Msg view model = p [] [ button [ onClick Increment ] [ text "+" ] , text (toString model) , button [ onClick Decrement ] [ text "-" ] ] ‑ 21 + 64 / 73
  65. 65. view : Int -> Html Msg view model = p [] [ button [ onClick Increment ] [ text "+" ] , text (toString model) , button [ onClick Decrement ] [ text "-" ] , button [ onClick Double ] [ text "2x" ] ] 65 / 73
  66. 66. view : Int -> Html Msg view model = p [] [ button [ onClick Increment ] [ text "+" ] , text (toString model) , button [ onClick Decrement ] [ text "-" ] , button [ onClick Double ] [ text "2x" ] ] -- NAMING ERROR ------------------------------------------------------- Main.elm Cannot find variable `Double` 82| , button [ onClick Double ] [ text "2x" ] 66 / 73
  67. 67. type Msg = Increment | Decrement | Double 67 / 73
  68. 68. type Msg = Increment | Decrement | Double -- MISSING PATTERNS --------------------------------------------------- Main.elm This `case` does not have branches for all possibilities. 68|> case msg of 69|> Increment -> 70|> model + 1 71|> 72|> Decrement -> 73|> model - 1 You need to account for the following values: Main.Double Add a branch to cover this pattern! 68 / 73
  69. 69. update : Msg -> Int -> Int update msg model = case msg of Increment -> model + 1 Decrement -> model - 1 Double -> model * 2 69 / 73
  70. 70. update : Msg -> Int -> Int update msg model = case msg of Increment -> model + 1 Decrement -> model - 1 Double -> model * 2 Success! Compiled 1 module. 70 / 73
  71. 71. A arquitetura do Elm te dá arantia de que todas as ações dos usuários estão previstas! 71 / 73
  72. 72. “Quem aprendeu al o novo hoje?” — Raymond Hettin er 72 / 73
  73. 73. Muito obri ado : ) @cuducos cuducos.me/blo Vamos aprender Elm! 73 / 73

×