O que há na programação funcional que faz a diferença?
A programação funcional é, por princípio, declarativa . Você diz qual é o seu resultado, em vez de como calculá-lo.
Vamos dar uma olhada na implementação realmente funcional do seu snippet. Em Haskell, seria:
predsum pred numbers = sum (filter pred numbers)
Está claro qual é o resultado? Bastante, é a soma dos números que atendem ao predicado. Como é calculado? Eu não ligo, pergunte ao compilador.
Você poderia dizer que usar sum
e filter
é um truque e não conta. Vamos implementá-lo sem esses ajudantes (embora a melhor maneira seja implementá-los primeiro).
A solução "Functional Programming 101" que não usa sum
é com recursão:
sum pred list =
case list of
[] -> 0
h:t -> if pred h then h + sum pred t
else sum pred t
Ainda está bem claro qual é o resultado em termos de chamada de função única. É 0
ou recursive call + h or 0
, dependendo pred h
. Ainda bem direto, mesmo que o resultado final não seja imediatamente óbvio (embora com um pouco de prática isso realmente pareça um for
loop).
Compare isso com a sua versão:
public int Sum(Func<int,bool> predicate, IEnumerable<int> numbers){
int result = 0;
foreach(var item in numbers)
if (predicate(item)) result += item;
return result;
}
Qual é o resultado? Oh, eu vejo: única return
declaração, sem surpresas aqui: return result
.
Mas o que é isso result
? int result = 0
? Não parece certo. Você faz algo mais tarde com isso 0
. Ok, você adiciona item
s a ele. E assim por diante.
É claro que, para a maioria dos programadores, isso é bastante óbvio, o que acontece em uma função simples como essa, mas adicione uma return
declaração extra ou algo assim e de repente fica mais difícil de rastrear. Todo o código é sobre como e o que resta para o leitor descobrir - esse é claramente um estilo muito imperativo .
Então, as variáveis e os loops estão errados?
Não.
Há muitas coisas que são muito mais fáceis de serem explicadas por eles e muitos algoritmos que exigem que o estado mutável seja rápido. Porém, as variáveis são inerentemente imperativas, explicando como, em vez de o quê , e dando pouca previsão de qual pode ser seu valor algumas linhas depois ou após algumas iterações de loop. Os loops geralmente exigem que o estado faça sentido e, portanto, são inerentemente imperativos.
Variáveis e loops simplesmente não são programação funcional.
Sumário
A programação funcional contemporânea é um pouco mais de estilo e um modo de pensar útil do que um paradigma. A forte preferência pelas funções puras está nessa mentalidade, mas na verdade é apenas uma pequena parte.
A maioria das linguagens comuns permite que você use algumas construções funcionais. Por exemplo, em Python, você pode escolher entre:
result = 0
for num in numbers:
if pred(result):
result += num
return result
ou
return sum(filter(pred, numbers))
ou
return sum(n for n in numbers if pred(n))
Essas expressões funcionais são adequadas para problemas desse tipo e simplesmente tornam o código mais curto (e menor é bom ). Você não deve substituir pensativamente o código imperativo por eles, mas quando eles se encaixam, eles quase sempre são uma escolha melhor.
item
variável sofre mutação no loop.