1. Padrões de Projeto em Linguagens
Funcionais
Italos Estilon e Layna Castro
2. O que é Programação Funcional?
Programação funcional é um paradigma de programação que trata
a computação como uma avaliação de funções matemáticas e que
evita estados ou dados mutáveis. Ela enfatiza a aplicação de
funções, em contraste da programação imperativa, que enfatiza
mudanças no estado do programa .
3. Por que Programação Funcional?
● Facilita a escrita de programas concorrentes
● A maioria dos programas são apenas problemas de
gerenciamento de dados.
● Programação Funcional é mais modular.
● Mais velocidade.
● A Programação Funcional é o retorno à simplicidade.
4. O que é Padrão de Projeto?
“Uma solução nomeada e catalogada para um
problema comum”
5. Padrões de Projeto em Programação Funcional
● Alguns acreditam que a Programação Funcional torna os
padrões de projeto obsoletos.
● Essa visão confunde o conceito de padrão com alguns padrões
de exemplo que podem ser desnecessários em Programação
Funcional.
● A Programação Funcional também possui seu próprio conjunto
de padrões.
6. Padrões de Projeto em Programação Funcional
Segundo Neal Ford, os padrões de projeto na Programação
Funcional se manifestam de uma dessas três maneiras:
● O padrão é absorvido pela linguagem.
● A solução padrão ainda existe no paradigma funcional, mas os
detalhes de implementação diferem.
● A solução é implementada usando recursos que outras
linguagens ou paradigmas não tem.
7. Fábricas e Currying
● Currying transforma uma função multiargument de modo que
ele pode ser chamado como uma cadeia de funções de
argumentos simples.
● No contexto de padrões de projeto, currying atua como uma
fábrica de funções.
● Graças às funções de primeira classe é fácil criar funções que
retornam outras funções baseado em algum critério, o que é a
essência da fábrica.
8. Exemplo de Fábrica
somador::Num a => a -> a-> a
somador x y = x + y
incrementador::Integer->Integer
incrementador = somador 1
● A função “incrementador” foi declarada como uma avaliação
parcial da função “somador”. Note que poderia ter sido
utilizada uma função anônima.
9. Exemplo de Fábrica
● Outro exemplo de fábrica:
filtro::[a]->(a->Bool)->[a]
filtro [] _ = []
filtro (a:xs) f
| f a = a:(filtro xs f)
| otherwise = filtro xs f
dividePor::Integral a => a->a->Bool
dividePor x y
|y `mod` x == 0 = True
|otherwise = False
multiposDeCinco = filtro [0..] (dividePor 5)
10. Exemplo de Fábrica
● A função “filtro” filtra uma lista de elementos com base em
uma função que recebe por parâmetro.
● A função que é passada é uma avaliação parcial da função
“dividePor”, que retorna “True” se o primeiro parâmetro divide
o segundo.
● A função que é passada para “filtro” é fabricada pelo Currying.
11. Template Method
● Outro padrão simplificado por funções de primeira classe.
● A função “map” recebe uma função e uma lista de elementos e aplica a função a cada
elemento da lista criando uma nova lista.
● “map” precisa apenas que a função passada seja do tipo “(a - > b)”.
● A operação específica de mapeamento é personalizada pelos argumentos da função.
map::(a->b)->[a]->[b]
map _ [] = []
map f (x:xs) = (f x):(map f xs)
quadradosPerfeitos = map ( x -> x*x) [0..]
12. Adapter
● Converte uma interface em uma outra esperada pelos clientes.
● Em Scala, pode ser implementado com o conceito de classe implícita.
● Quando o tipo esperado é “Log”, mas uma instância de “Logger” é usada, o
compilador Scala irá automaticamente envolver essa instância na classe adaptador.
trait Log {
def warning(message: String)
def error(message: String)
}
final class Logger {
def log(level: Level, message: String) { /* ... */ }
}
implicit class LoggerToLogAdapter(logger: Logger) extends Log {
def warning(message: String) { logger.log(WARNING, message) }
def error(message: String) { logger.log(ERROR, message) }
}
val log: Log = new Logger()
13. Memoization
● Memoização é uma técnica para armazenar valores de uma
função em vez de refazer os cálculos cada vez que a função é
chamada.
memoized_fib :: Int -> Integer
memoized_fib = (map fib [0 ..] !!)
where fib 0 = 0
fib 1 = 1
fib n = memoized_fib (n-2) + memoized_fib(n-1)
14. Correspondência de Padrões
● Correspondência de padrões consiste na pesquisa por padrões
em determinados dados e, caso tenha sucesso, fazer algo com o
ele.
● Abordagem funcional para o padrão de projeto Visitor.
delete::(Eq a) => a -> [a] -> [a]
delete a [] = []
delete a [x] = if a == x then [] else [x]
delete a (x:xs) = [] ++ if (x == a) then xs else x:(delete a xs)
15. Fold
● Refere-se a uma família de funções de ordem superior que
analisam a estrutura de dados recursiva e recombinam através
do uso de uma determinada operação, combinando os
resultados de forma recursiva processando suas partes
constituintes, construindo-se um valor de retorno.
foldL::(a -> b -> a) -> a -> [b] -> a
foldL _ a [] = a
foldL f a (x:xs) = foldL f (f a x) xs
16. Referências
● WAMPLER, Dean. programação funcional para desenvolvedores Java. São Paulo, SP:
Novatec, 2012. 112 p. ISBN 9788575223161 (broch.).
● http://www.ibm.com/developerworks/library/j-ft10/
● http://http://en.wikipedia.org/wiki/Fold_(higher-order_function)
● http://haskell.tailorfontela.com.br/
● http://www.ibm.com/developerworks/java/library/j-ft11/index.html
● http://www.ibm.com/developerworks/java/library/j-ft12/index.html
● https://pavelfatin.com/design-patterns-in-scala/#adapter
● https://www.haskell.org/haskellwiki/Memoization