詳細検索

Introdução à Programação Funcional

Avatar
por Chen Ziyu
4 min de leitura

Introdução à Programação Funcional
Traduzido do English • Ver original

O primeiro paradigma de programação que a maioria dos programadores do século XXI aprende provavelmente é a Programação Orientada a Objetos (ou POO, para abreviar). A Programação Orientada a Objetos nos permite transformar entidades do mundo real em modelos altamente abstratos com propriedades descritivas e métodos executáveis para simular seus comportamentos no mundo real. Apesar de suas inúmeras vantagens, como legibilidade, reutilização e manutenção, também introduz imensa complexidade na gestão de estados. A dificuldade em acompanhar os estados dos objetos levou programadores exaustos e intrigados a produzir código propenso a erros e causar bugs que levariam horas, ou até dias, para serem localizados e corrigidos. "Existe uma saída para essa situação indesejável?", você pode perguntar. Aqui está a boa notícia: um paradigma de programação menos conhecido, porém amplamente utilizado, chamado Programação Funcional (ou FP, para abreviar) pode ajudar a inverter o rumo e diminuir o número de bugs que causamos. Neste artigo, explicarei o que é Programação Funcional e por que ela pode nos ajudar a evitar bugs.

Programação Funcional: Pura como Ouro, Não Tem Mais Bugs

Programação funcional é um paradigma de programação que busca alcançar os seguintes dois objetivos:

  1. Garantir que entradas e saídas sempre tenham uma relação determinística
  2. Eliminar efeitos colaterais, incluindo mutações de estado e fluxos de I/O

A motivação final por trás dessa abordagem determinística e sem efeitos colaterais é facilitar o raciocínio sobre código e dificultar a introdução de bugs. Nenhuma surpresa desagradável virá se as mesmas entradas sempre gerarem as mesmas saídas. Também não precisamos acompanhar como cada estado muda de valor em diferentes estágios se livrarmos nossa base de código dos efeitos colaterais.

A programação funcional faz uso intenso de funções puras para alcançar os objetivos mencionados acima. Funções puras possuem as seguintes duas propriedades:

1. Funções puras sempre retornam os mesmos valores para os mesmos argumentos

Ter esse mapeamento determinístico entre entradas e saídas traz uma vantagem óbvia: podemos sempre contar com funções puras para devolver nossos resultados esperados. Essa certeza nos impede de causar bugs que resultam de funções retornando resultados inesperados.

2. Funções puras não produzem efeitos colaterais

A regra dos efeitos colaterais estipula que cada função pura não deve causar mudanças fora de seu escopo. Essa regra ajuda a eliminar modificações externas de estado feitas por funções não puras, que constituem outra grande fonte de bugs porque as modificações feitas por funções não puras são menos evidentes e podem facilmente escapar à nossa atenção.

Agora vamos analisar alguns exemplos de funções não puras e funções puras.

Funções Não Puras

num1 = 5
def add(num2: int) -> int: 
    Global Num1
    retorne num1 + num2

# Primeira execução
print(add(3)) # retorna 8
num1 = 3
# Segunda execução
print(add(3)) # retorna 6

A função 'adicionar' no exemplo de código acima não é pura porque não produz consistentemente as mesmas saídas com as mesmas entradas.

produto = 0
def multiply_by_two(num: int) -> int: 
    Produto Global
    Produto = num * 2
    Devolução do produto

# Primeira execução
print(multiply_by_two(3)) # retorna 6
Impressão (produto)
# Segunda execução
Print(multiply_by_two(5)) # retorna 10
Impressão (produto)
# Terceira execução
print(multiply_by_two(3)) # retorna 6
Impressão (produto)

A função 'multiply_by_two' neste exemplo de código retorna as mesmas saídas dadas as mesmas entradas. No entanto, ainda não é uma função pura porque modifica a variável 'produto' em cada invocação, o que viola a regra sem efeitos colaterais.

Funções Puras

def add_five(num2: int) -> int: 
    retorne num2 + 5

# Primeira execução
print(add(3)) # retorna 8
# Segunda execução
print(add(3)) # retorna 8

Diferente da função 'adicionar' anterior, a função 'add_five' aqui é pura porque o mapeamento entre entradas e saídas é determinístico.

def multiply_by_two(num: int) -> int: 
    retorno número * 2

# Primeira execução
print(multiply_by_two(3)) # retorna 6
Impressão (produto)
# Segunda execução
print(multiply_by_two(3)) # retorna 6
Impressão (produto)

Neste exemplo de código, a função 'multiply_by_two' é pura. Ela sempre retorna as mesmas saídas com as mesmas entradas. Além disso, não tem efeitos colaterais.

Aviso:

Uma coisa a se notar: você não precisa abrir mão de outros paradigmas de programação, como a Programação Orientada a Objetivos, para aproveitar a Programação Funcional. Sinta-se à vontade para combinar programação funcional com outros paradigmas da forma que achar melhor!

Resumo

Neste artigo, apresentei brevemente o que é Programação Funcional e como ela utiliza funções puras. Também expliquei por que o uso de funções puras na Programação Funcional pode nos ajudar a evitar criar bugs sem saber. Espero que este artigo tenha ajudado você a dar um pontapé inicial na sua programação funcional.

Related Articles