Introdução
Antes de me aventurar por esse fantástico mundo funcional, a primeira coisa que me vinha à mente era usar somente recursão para resolver problemas, mas acabei aprendendo que não é apenas isso.
Programação Funcional ou FP(Functional Programming) é um paradigma de programação declarativo; paradigma é uma forma ou padrão de escrita de código e declarativo refere-se ao fato de usar expressões em vez de ditar um passo a passo.
Foi um dos primeiros paradigmas criados, mas devido ao alto custo de memória para a época se tornou pouco utilizado. Por conta do grande aumento da capacidade de hardware, hoje o paradigma funcional voltou em um crescente uso em produção.
Efeitos colaterais
Um fato que tem que se ter em mente sobre FP é o objetivo de evitar ao máximo efeitos colaterais(side effects), exemplos práticos disso seria uma requisição ao banco de dados, uma requisição HTTP ou qualquer operação de entrada/saída. Em outras palavras, tenta-se diminuir o grau de imprevisibilidade do código. Isso nos leva ao princípio de funções puras.
Funções Puras
Funções puras retornam sempre o mesmo valor para os mesmos parâmetros e a sua execução não gera mudança no escopo fora dela. Esse comportamento é possível devido ao fato de que elas não são afetadas pelo estado externo nem interno, ou seja, tudo que a função precisa é passado para ela.
def pure_increment(elements, index):
new_elements = elements.copy()
new_elements[index] += 1
return new_elements
elements = [1, 2, 3]
pure_increment(elements, 0)
#Function return: [2, 2, 3]
pure_increment(elements, 0)
#Function return: [2, 2, 3]
pure_increment(elements, 0)
#Function return: [2, 2, 3]
No exemplo acima a função pure_increment irá incrementar o valor de um elemento em uma lista. E para torná-la pura passamos a lista e o índice da lista que será incrementado. Mas isso não é o suficiente. Vale lembrar de um fato importante: a lista no escopo da função ainda referencia a original, ou seja, qualquer mudança nela irá refletir na primeira, impossibilitando a pureza da função, recordando que uma função pura só pode operar com o que existe dentro do escopo da mesma. Por isso na linha 2 foi criado um cópia da lista usada, agora qualquer mudança nessa cópia não irá afetar a original.
Done!
Vimos o que se fazer, mas é bom saber o que não fazer:
def impure_increment(elements, index):
elements[index] += 1
return elements
elements = [1, 2, 3]
impure_increment(elements, 0)
#Function return: [2, 2, 3]
impure_increment(elements, 0)
#Function return: [3, 2, 3]
impure_increment(elements, 0)
#Function return: [4, 2, 3]
Acima não foi criada uma cópia da lista passada para a função, e como resultado temos um efeito colateral. Como a lista elements
do escopo global é mudada dentro da função, a cada nova chamada da função passando elements
retornará um resultado diferente. O mesmo efeito colateral poderia ocorrer com uso da palavra chave global
para acessar diretamente elements
no escopo global.
Deixando seu código mais funcional
Python tem um conjunto de funções built-in
puras, como map
, filter
,e sorted
, que não irão alterar a estrutura do objeto usado, elas também são funções de alta ordem, mas isso é assunto para outro momento. Essas funções podem muitas vezes substituir loops simples deixando o código com um estilo funcional, mas a tentativa de compactar em uma linha pode tornar o código de difícil compreensão.
#Functional way
elements = {1: 'one', 2: 'two', 3: 'three', 4: 'four'}
dict(filter(lambda element: element[0] % 2 == 0, elements.items()))
#{2: 'two', 4: 'four'}
#Imperative way
for key in elements:
if elements[key] % 2 != 0:
del(elements[key])
#elements = {2: 'two', 4: 'four'}
No exemplo acima vemos uma forma de filtrar elementos pares do dicionário de uma forma simples e pura usando filter
e um contra exemplo imperativo impuro.
Em aplicações práticas não é possível criar um código 100% puro, pois efeitos colaterais são necessários para permitir a comunicação com o ambiente externo. Então o máximo que pode ser feito é concentrar a impureza em trechos específicos da aplicação. Vale ressaltar o fato de que funções puras tornam o código bem mais fácil de testar e de fazer debug, pois os efeitos colaterais estarão em “locais” específicos do código.
Be FUNctional!
“Do or Do not. There is no try” — Yoda
Top comments (0)