qual a definição de fatorial? um matemático poderia me responder algo assim:
fatorial(1) = 1 fatorial(n :: n Inteiro, n > 1) = n * fatorial(n-1)
como eu represento isso numa linguagem de programação? se você está acostumado com linguagens imperativas, poderia escrever um programa desse tipo:
fatorial(n): var resultado = 1 for i = 1 → n resultado ← resultado * i return resultado
no entanto, numa linguagem funcional, a resposta do matemático já é uma resposta! por exemplo, em Haskell, eu realmente escreveria dessa forma:
fatorial :: Integer -> Integer fatorial 1 = 1 fatorial n = n * (fatorial (n - 1))
a ideia é que uma operação seja vista como um encadeamento de pequenas operações que podem ser vistas como aplicações de "regras" — em oposição a operações algorítmicas que são vistas como sequências de passos.
um dos grandes lances de usar programação funcional é que uma função SEMPRE devolva o mesmo resultado dadas as mesmas entradas, e que a função não tenha ~efeitos colaterais~. então ela não pode mexer em variáveis externas, nem com qualquer coisa que tenha um ~estado~.
essa função aqui embaixo tem efeitos colaterais, por exemplo. isso não é permitido numa linguagem puramente funcional.
(em algum lugar...) massaSolarKg = 1.98892e+30 (mais adiante...) fatorial(n): var resultado = 1 for i = 1 → n resultado ← resultado * i massaSolarKg ← massaSolarKg * i return resultado (cuidado! talvez algum buraco negro surja ao executar esta linha...) print fatorial(100)
suponha que eu tenha um array de frutas e outro array com o mesmo tamanho dizendo a quantidade de cada fruta que tem na minha fruteira:
frutas = ["banana", "laranja", "limão", "pêssego", "abacate"] estoque = [3, 7, 11, 5, 18]
agora quero saber quais frutas estão em excesso. numa linguagem imperativa eu posso fazer algo com a seguinte lógica:
for i = 1 → num(frutas) if estoque[i] > 10 print "Tem " + frutas[i] + " pra caramba!"
ou seja, eu escrevi pro computador um algoritmo passo a passo do que ele deve fazer. uma sequência de passos que ele deve executar.
agora vamos traduzir isso para uma pseudo-linguagem funcional. para facilitar o entendimento inicial, vou decompor em etapas. apesar de haver uma sequência, não é uma sequência de passos! é apenas uma sequência de definições que se encadeiam. as linhas com >>>
indicam o resultado de cada etapa.
frutas = ["banana", "laranja", "limão", "pêssego", "abacate"] estoque = [3, 7, 11, 5, 18] mensagem_fruta(nomeFruta, estoqueFruta) := { "Tem " + nomeFruta + " pra caramba!" } se estoqueFruta > 10 { nulo } caso contrário mensagens = [mensagem_fruta(frutas[i], estoque[i]) | i = 1 → num(frutas)] >>> [nulo, nulo, "Tem limão pra caramba!", nulo, "Tem abacate pra caramba!"] mensagens_para_imprimir = filtraNaoNulo(mensagens) >>> ["Tem limão pra caramba!", "Tem abacate pra caramba!"] mensagem_para_imprimir = junta("\n", mensagens_para_imprimir) >>> "Tem limão pra caramba!\nTem abacate pra caramba!"
dá pra eu resumir tudo isso em um passo só:
frutas = ["banana", "laranja", "limão", "pêssego", "abacate"] estoque = [3, 7, 11, 5, 18] mensagem_para_imprimir = junta("\n", filtraNaoNulo([ { "Tem " + frutas[i] + " pra caramba!" } se estoque[i] > 10 { nulo } caso contrário | i = 1 → num(frutas)]))
que é toda a ideia da programação funcional: essa operação que eu fiz se resume a um encadeamento de funções.
nesse exemplo a versão funcional acaba ficando mais longa — a ideia era pegar um exemplo simples qualquer e traduzir as ideias para o pensamento funcional. mas há de fato muitos casos em que o estilo de programação mais funcional acaba de fato compactando o código, ou no mínimo deixando-o mais organizado e legível.