1. A introdução apresenta programação funcional e o autor Arthur Xavier.
2. Os benefícios da programação funcional incluem previsibilidade, testabilidade, facilidade de raciocínio e simplicidade.
3. O documento discute conceitos como funções puras, imutabilidade, tipos, composição e recursividade.
4. Não é somente programar com funções.
É um paradigma de programação declarativo.
Modela computações como o resultado da avaliação e composição de funções.
Evita dados mutáveis e efeitos colaterais.
Mas o que é programação funcional?
14. Funções
Seja um conjunto tal que:
ε ∈ ,
∀ x ∈ ℤ, ∀ α ∈ , x • α ∈ .
Então
squareL : → = α ↦
ε se α = ε
x² • squareL(β) se α = x • β
sumL : → ℤ = α ↦
0 se α = ε
x + sumL(β) se α = x • β
15. (Elm) Funções
squareList : List Int -> List Int
squareList l =
case l of
[] -> []
x :: xs -> x^2 :: squareList xs
sumList : List Int -> Int
sumList l =
case l of
[] -> 0
x :: xs -> x + sumList xs
16. Toda função é pura.
Funções impuras são chamadas de procedimentos, rotinasou subrotinas.
Funções puras
17. Uma função pura é uma função que sempre produz o mesmo resultado quando são
passados os mesmos argumentos, e que não produz efeitos colaterais observáveis.
Funções puras
18. Efeitos colaterais
“Uma função ou expressão produz efeitos colaterais se ela modifica algum estado
fora de seu escopo ou realiza alguma interação observável com as funções que a
chamaram ou com o mundo externo.”
– Wikipedia
24. Função pura
const square = x => x*x;
const add = (a, b) => a + b;
function sumOfSquares(array) {
return array
.map(square)
.reduce(add, 0);
}
console.log(sumOfSquares([2, 3, 5]));
25. (Elm) Função pura
sumOfSquares : List Int -> Int
sumOfSquares list =
let
square x = x*x
in
List.foldl (+) 0 (List.map square list)
-- cadê o console.log??
28. Linguagens funcionais implementam funções de primeira classe.
Funções em linguagens funcionais são valores.
Funções podem ser passadas como argumentos para outras funções.
Funções podem ser valores de retorno de outras funções.
Funções de primeira classe
29. São funções que recebem outras funções como argumento.
map
reduce / fold
filter
Funções de alta ordem
30. Funções de alta ordem
sumOfSquares : List Int -> List Int
sumOfSquares list =
let
square x = x*x
in
List.foldl (+) 0 (List.map square list)
31. Função de alta ordem
map : (a -> b) -> List a -> List b
map f l =
case l of
[] -> []
x :: xs -> f x :: map f xs
32. Lambda
sumOfSquares : List Int -> List Int
sumOfSquares list = List.foldl (+) 0 (List.map (x -> x*x) list)
34. Transforma a avaliação de uma função de vários argumentos na avaliação de uma
sequênciade funções de um argumento.
Facilita o uso de funções de vários argumentos e a aplicação parcial de funções.
Currying
f : ℤ × ℤ → ℤ ~ f : ℤ → ℤ → ℤ
35. Currying
addT : (Int, Int) -> Int
addT (a, b) = a + b
add : Int -> Int -> Int
add a b = a + b
-- add2 :: Int -> Int
add2 = add 2
-- five :: Int
five = add2 3 -- == 5
36. Mecanismo que combina funções simples para construir outras mais complexas.
Encoraja a fatoração de funções para melhor manutenção e reuso de código.
Composição de funções
( f ∘ g)(x) = f (g(x))
37. Operador de composição de funções
compose : (a -> b) -> (b -> c) -> (a -> c)
compose f g = a -> f (g a)
38. (point free) Composição de funções
squareList : List Int -> List Int
squareList = List.map (x -> x*x)
sumList : List Int -> List Int
sumList = List.foldl (+) 0
sumOfSquares : List Int -> List Int
sumOfSquares = sumList << squareList
39. Composição de funções
squareList : List Int -> List Int
squareList xs = List.map (x -> x*x) xs
sumList : List Int -> List Int
sumList xs = List.foldl (+) 0 xs
sumOfSquares : List Int -> List Int
sumOfSquares xs = (sumList << squareList) xs
40. Conjuntos de valores(não são classes).
Podem ser compostos.
Seus valores construídos e desestruturados(com pattern matching).
Garantem segurança.
Tipos
41. Construídos como operações algébricas sobre conjuntos.
Permitem a definição de tipos mais complexos.
Permitem a composição de tipos.
Tipos algébricos
42. Tipo soma e função com pattern matching
type PrimaryColor = Red | Blue | Yellow
nextColor : PrimaryColor -> PrimaryColor
nextColor color =
case color of
Red -> Blue
Blue -> Yellow
Yellow -> Red
43. Tipo produto e função com desestruturação
type Point = Point Int Int -- mkPoint : Int -> Int -> Point
addPoints : Point -> Point -> Point
addPoints (Point x1 y1) (Point x2 y2) = Point (x1 + x2) (y1 + y2)
44. (Elm) Records
type alias User = { name : String, email : String }
maria : User
maria = { name = "Maria", email = "maria@email.com" }
type User = User { name : String, email : String } type User = User String String~
45. Tipos recursivos
type List = Nil | Cons Int List
type NonEmptyList = Single Int | Cons Int List
type Tree = Tree String (List Tree)
type BTree = Empty | NodeLeft String BTree | NodeRight String BTree
46. Pattern matching em tipos recursivos
mapList : (Int -> Int) -> List -> List
mapList f l =
case l of
Nil -> Nil
Cons x xs -> Cons (f x) (mapList f xs)
mapList : (Int -> Int) -> List -> List
mapList f Nil = Nil
mapList f Cons x xs = Cons (f x) (mapList f xs)
mapTree : (String -> String) -> Tree -> Tree
mapTree f t =
case t of
Empty -> Empty
NodeLeft x xs -> NodeLeft (f x) (mapTree f xs)
NodeRight x xs -> NodeRight (f x) (mapTree f xs)
47. Tipos paramétricos
type Point a = Point a a
type Tuple a b = Tuple a b
p : Point Int
p = Point 1 3
p2 : Point Float
p2 = Point 1.2 3.4
user : Tuple Int String
user = Tuple 1 "Maria"
48. Tipos recursivos paramétricos
type List a = Nil | Cons a List -- mkCons : a -> List -> List
type NonEmptyList a = Single a | Cons a List
type Tree a = Tree a (List Tree)
type BTree a = Empty | NodeLeft a BTree | NodeRight a BTree
49. Tipos paramétricos e funções
type Maybe a = Nothing | Just a
type Either a b = Left a | Right b
head : List a -> Maybe a
head = …
parseMarkdown : String -> Either Error Markdown
parseMarkdown = …
50. Tipo soma e função parcial
type SecondaryColor = Orange | Green | Purple
addPrimaryColors : PrimaryColor -> PrimaryColor -> SecondaryColor
addPrimaryColors c1 c2 =
case (c1, c2) of
(Red, Blue) -> Purple
(Red, Yellow) -> Orange
(Blue, Red) -> Purple
(Blue, Yellow) -> Green
(Yellow, Red) -> Orange
(Yellow, Blue) -> Green
51. Tipo soma e função
type SecondaryColor = Orange | Green | Purple
addPrimaryColors : PrimaryColor -> PrimaryColor -> Either PrimaryColor SecondaryColor
addPrimaryColors c1 c2 =
case (c1, c2) of
(Red, Blue) -> Right Purple
(Red, Yellow) -> Right Orange
(Blue, Red) -> Right Purple
(Blue, Yellow) -> Right Green
(Yellow, Red) -> Right Orange
(Yellow, Blue) -> Right Green
_ -> Left c1
52. Tipo inseguro
type Permission = BlockUser | BanUser | RemovePosts
type UserType = Guest | User | Admin
type alias User =
{ name : Maybe String
, email : Maybe Email
, permissions : List Permission
, userType : UserType
}
53. Tipo seguro
type Permission = BlockUser | BanUser | RemovePosts
type User
= Guest
| User
{ name : String
, email : Email
}
| Admin
{ name : String
, email : Email
, permissions : List Permission
}
54. Tipo seguro++
type Permission = BlockUser | BanUser | RemovePosts
type User p
= Guest
| User
{ name : String
, email : Email
}
| Admin
{ name : String
, email : Email
, permissions : p
}
55. Ter de tratar todos os valores possíveis de um tipo ajuda a entender o domínio.
Quando uma função é parcial pode-se restringir sua entrada ou sua saída.
“Ah,vocênãosabiaqueessalistanãopodiaservazia?Culpasua!
ArrayOutOfBoundsException!!”
— Java Enterprise Edition
Totalidade
56. Funções totais
head : List a -> Maybe a
head = …
head : NonEmptyList a -> a
head = …~
57. Resolve problemas causados por estados mutáveis:
Condições de corrida, complexidade, imprevisibilidade…
Linguagens funcionais puras representam mutabilidade como efeito colateral.
Elm nem mesmo permitem mutabilidade.
Imutabilidade
58. Coleções como listas ou árvores são úteis para representar iterações sobre dados.
Mais do que isso elas permitem transformar múltiplos valores em outro tipo.
Coleções
59. Funções úteis do tipo List
head : List a -> Maybe a
tail : List a -> Maybe (List a)
range : Int -> Int -> List Int
(::) : a -> List a -> List a
append : List a -> List a -> List a
sort : List comparable -> List comparable
map : (a -> b) -> List a -> List b
map2 : (a -> b -> c) -> List a -> List b -> List c
foldr : (a -> b -> b) -> b -> List a -> b
foldl : (a -> b -> b) -> b -> List a -> b
filter : (a -> Bool) -> List a -> List a
60. Estruturas algébricas que implementam a operação map e seguem as leis:
map : (a -> b) -> f a -> f b
map id = id
map (f << g) = map f << map g
Functores
61. São contêineres que representam resultados de computações sobre outros tipos.
As computações representadas pelo functor são definidas pela forma do functor e
pelo comportamento da operação map.
Functores
62. Maybe
type Maybe a = Nothing | Just a
map : (a -> b) -> Maybe a -> Maybe b
map f maybe =
case maybe of
Nothing -> Nothing
Just a -> Just (f a)
63. Either
type Either a = Left a | Right a
map : (a -> b) -> Either a -> Either b
map f either =
case either of
Left a -> Left a
Right a -> Right (f a)
64. Tuple
map : (a -> b) -> (t, a) -> (t, b)
map f (tag, a) = (tag, f a)
65. List
map : (a -> b) -> List a -> List b
map f list =
case list of
[] -> []
x :: xs -> f x :: map f list
69. Nesta primeira parte vamos apenas inserir notas no modelo e mostrá-las como
elementos Html na tela.
Vamos também inserir novas notas no modelo ao clicar em um botão.
Parte 1
70. Nesta segunda parte vamos tratar a edição de notas.
Quando o usuário clicar em uma nota deveremos poder editá-la. Ao pressionar
Enter, as modificações devem ser salvas no modelo.
Será necessário modificar o modelo para que seja possível identificar qual nota está
sendo editada no momento.
Parte 2
71. Nesta terceira parte veremos como Elm trata efeitos colaterais através de ports.
Faremos com que nossa aplicação salve o modelo quando ele for alterado no local
storage do browser.
Parte 3
72. Uma port em Elm é um valor ou função definido com a keyword port que deve
produzir um valor do tipo Cmd, um comando.
Precisaremos definir uma port que envia o modelo a ser salvo para o mundo externo.
Por conveniência já foi feito no arquivo index.html o tratamento dos comandos
recebidos pela port que iremos definir.
Parte 3
73. Nesta quarta parte veremos os benefícios dos tipos paramétricos.
Parametrizaremos o tipo Noteem relação a um tipo i que representa o campo de
identificação de uma nota.
Parte 4
74. Nesta quinta e última parte parametrizaremos o tipo Note em relação ao conteúdo.
Para que possamos usar tipos que não sejam String para representar o tipo de uma
nota, mas mantendo o tipo String como conteúdo das notas serializadas, devemos
parametrizar o tipo Note em relação ao conteúdo e tornar as funções que operam
sobre ele polimórficas sobre o conteúdo.
Parte 5
75. Recursos
An Introduction to Elm
http://guide.elm-lang.org/
Elm Examples
http://elm-lang.org/examples
Elm Search
https://klaftertief.github.io/elm-search/
Elm Packages
http://package.elm-lang.org/
https://github.com/arthur-xavier/workshop-intro-fp-elm