O documento discute como a programação funcional pode ser uma ferramenta útil para controlar a complexidade de programas. Apresenta abstrações funcionais como monóides e mônadas que permitem expressar programas de forma mais concisa e abstrata, facilitando a composição e raciocínio sobre corretude.
5. Arthur Xavier
Estudante de Ciência da Computação;
Apaixonado por programação funcional;
Membro ativo da comunidade FP;
Desenvolvendo com Phil Freeman uma formalização
de interfaces de usuário declarativas com Comonads;
6. OU COMO
PROGRAMAÇÃO FUNCIONAL É UMA ÓTIMA FERRAMENTA PARA CONTROLE
DE COMPLEXIDADE.
PROGRAMAS E FUNÇÕES
SOBRE
PENSANDO EM ABSTRAÇÃO,
7. Outline
Por que programação funcional;
Abstrações funcionais;
Complexidade sem dificuldade:
1. Monóides;
2. Mônadas.
10. comando1();
comando2(); // mudança de estado
variável = comando3(); // estado privado
if (variável.atributo)
exceção!
envia_email(); // mudança de estado
lança_míssil();
return variável;
13. Linguagens convencionais
Semântica sequencial de transições de estado;
Divisão entre mundo das expressões vs. comandos;
Dificuldade de combinar programas;
Ausência de propriedades matemáticas.
32. Conjunto S com uma operação binária •, tal que
1. ∀a,b ∈ S : a•b ∈ S. (fechamento)
2. ∀a,b,c ∈ S : (a•b)•c = a•(b•c). (associatividade)
3. ∃e ∈ S : ∀a ∈ S : e•a = a•e = a. (identidade)
49. HASKELL
data Add = Add Int
instance Monoid Add where
Add a <> Add b = Add (a + b)
mempty = Add 0
…
data Mult = Mult Int
instance Monoid Mult where
Mult a <> Mult b = Mult (a * b)
mempty = Mult 1
50. HASKELL
data Add a = Add a
instance Num a => Monoid (Add a) where
Add a <> Add b = Add (a + b)
mempty = Add 0
…
data Mult a = Mult a
instance Num a => Monoid (Mult a) where
Mult a <> Mult b = Mult (a * b)
mempty = Mult 1
51. HASKELL
instance (Monoid a, Monoid b) => Monoid (a, b) where
(a1, b1) <> (a2, b2) = (a1 <> a2, b1 <> b2)
mempty = (mempty, mempty)
52. HASKELL
data Max a = Max a
instance Ord a => Monoid (Max a) where
Max a <> Max b = Max (if a < b then a else b)
mempty = Max ??
53. HASKELL
data Max a = Max a
instance (Ord a, Bounded a) => Monoid (Max a) where
Max a <> Max b = Max (if a < b then a else b)
mempty = Max minBound
54. HASKELL
foldMap :: Monoid m => (a -> m) -> [a] -> m
foldMap f [] = mempty
foldMap f (a:as) = f a <> foldMap f as
59. HASKELL
data Builder a = Builder (a -> a)
instance Monoid (Builder a) where
Builder f <> Builder g = Builder (f . g)
mempty = Builder id
build :: a -> Builder a -> a
build def (Builder builder) = builder def
62. Disjunção de predicados;
Conjunção de predicados;
Conjuntos com união;
Composição de opções;
Combinação de regras;
Interseção de formas bidimensionais;
Funções que retornam monóides;
Combinação de máquinas de estado;
66. HASKELL
add1 :: Int -> (Int, String)
add1 x = (x + 1, "+1")
mul3 :: Int -> (Int, String)
mul3 x = (x * 3, "*3")
-- deseja-se
add1 30 ?? mul3 ?? add1 = (94, "+1*3+1")
-- mas o que é (??)
67. HASKELL
add1 :: Int -> (Int, String)
add1 x = (x + 1, "+1")
mul3 :: Int -> (Int, String)
mul3 x = (x * 3, "*3")
-- ou ainda
do
x <- add1 30
y <- mul3 x
add1 y
68. HASKELL
add1 :: Int -> (Int, String)
add1 x = (x + 1, "+1")
mul3 :: Int -> (Int, String)
mul3 x = (x * 3, "*3")
-- deseja-se
add1 30 ?? mul3 ?? add1 = (94, "+1*3+1")
-- mas o que é (??)
82. HASKELL
data Writer a = Writer (a, String)
instance Monad Writer where
pure a = Writer (a, "")
Writer (a, s) >>= f = Writer (b, s ++ s2)
where
Writer (b, s2) = f a
83. HASKELL
data Writer s a = Writer (a, s)
instance Monoid s => Monad (Writer s) where
pure a = Writer (a, mempty)
Writer (a, s) >>= f = Writer (b, s <> s2)
where
Writer (b, s2) = f a
84. HASKELL
add1 :: Int -> Writer String Int
add1 x = Writer (x + 1, "+1")
mul3 :: Int -> Writer String Int
mul3 x = Writer (x * 3, "*3")
add1 30 >>= mul3 >>= add1 = (94, "+1*3+1")
85. HASKELL
add1 :: Int -> Writer String Int
add1 x = Writer (x + 1, "+1")
mul3 :: Int -> Writer String Int
mul3 x = Writer (x * 3, "*3")
do
x <- add1 30
y <- mul3 x
add1 y
86. HASKELL
tell :: Monoid s => s -> Writer s ()
tell s = Writer ((), s)
add1 x = do { tell "+1"; pure (x + 1) }
mul3 x = do { tell "*3"; pure (x * 3) }
do
x <- add1 30
y <- mul3 x
add1 y
88. HASKELL
data State s a = State (s -> (a, s))
instance Monad (State s) where …
put :: s -> State s ()
put s = _ -> ((), s)
get :: State s s
get = s -> (s, s)
modify :: (s -> s) -> State s ()
modify f = s -> ((), f s)
89. HASKELL
put :: s -> State s ()
get :: State s s
modify :: (s -> s) -> State s ()
…
add1 x = do
modify (log -> log <> "+1")
pure (x + 1)
mul3 x = do
modify (log -> log <> "*3")
pure (x * 3)
90. HASKELL
do
x <- add1 30
y <- mul3 x
add1 y
do
x <- add1 30
y <- mul3 x
log <- get
add1 y
92. HASKELL
data Maybe a = Nothing | Just a
instance Monad Maybe where …
head :: [a] -> Maybe a
…
tryGetLastPhoto username = do
user <- tryGetUser username
photos <- tryGetPhotos user
head photos
100. HASKELL
data Parser a = Parser (String -> [(a, String)])
instance Monad Parser where …
char :: Parser Char
char = Parser f
where
f [] = []
f (c:cs) = [(c, cs)]
zero :: Parser a
zero = Parser (_ -> [])
102. HASKELL
satisfy :: (Char -> Bool) -> Parser Char
satisfy pred = do
c <- char
if pred c then pure c else zero
alt :: Parser a -> Parser a -> Parser a
alt (Parser p) (Parser q) = Parser $ s ->
case p s of
[] -> q s
res -> res
some :: Parser a -> Parser [a]
some parser = -- one or many
103. HASKELL
digit :: Parser Char
digit = satisfy isDigit
number :: Parser Int
number = do
cs <- some digit
pure (read cs)
104. HASKELL
add :: Parser Int
add = do
a <- number
satisfy (== '+')
b <- number
pure (a + b)
sub :: Parser Int
sub = do
a <- number
satisfy (== '-')
b <- number
pure (a - b)
105. HASKELL
expression :: Parser Int
expression = alt add sub
parse (Parser f) = f
parse expression "10+4" = 14
parse expression "10-4" = 6