Qu'est-ce qui fait la différence dans la programmation fonctionnelle?
La programmation fonctionnelle est par principe déclarative . Vous dites quel est votre résultat au lieu de savoir comment le calculer.
Jetons un coup d'œil à l'implémentation vraiment fonctionnelle de votre extrait. À Haskell, ce serait:
predsum pred numbers = sum (filter pred numbers)
Est - il clair que le résultat est? Tout à fait ainsi, c'est la somme des nombres rencontrant le prédicat. Comment est-il calculé? Je m'en fiche, demandez au compilateur.
Vous pourriez peut-être dire que l'utilisation de sum
et filter
est une astuce et cela ne compte pas. Laissez-le ensuite implémenter sans ces aides (bien que la meilleure façon serait de les implémenter en premier).
La solution "Functional Programming 101" qui n'utilise pas sum
est à récursivité:
sum pred list =
case list of
[] -> 0
h:t -> if pred h then h + sum pred t
else sum pred t
Il est encore assez clair quel est le résultat en termes d'appel de fonction unique. C'est soit 0
, soit recursive call + h or 0
, selon pred h
. Toujours assez simple, même si le résultat final n'est pas immédiatement évident (bien qu'avec un peu de pratique, cela se lit vraiment comme une for
boucle).
Comparez cela à votre version:
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;
}
Quel est le résultat? Oh, je vois: seule return
déclaration, pas de surprise ici: return result
.
Mais c'est quoi result
? int result = 0
? Cela ne semble pas correct. Vous faites quelque chose plus tard avec ça 0
. Ok, vous y ajoutez des item
s. Etc.
Bien sûr, pour la plupart des programmeurs, c'est assez évident ce qui se passe dans une fonction simple comme celle-ci, mais ajoutez une return
instruction supplémentaire ou plus et il devient soudainement plus difficile à suivre. Tout le code consiste à savoir comment et ce qu'il reste au lecteur à comprendre - c'est clairement un style très impératif .
Alors, les variables et les boucles sont-elles incorrectes?
Non.
Il y a beaucoup de choses qui sont beaucoup plus faciles à expliquer par eux, et de nombreux algorithmes qui nécessitent un état mutable pour être rapide. Mais les variables sont intrinsèquement impératives, expliquant comment au lieu de quoi , et donnant peu de prédiction de ce que leur valeur peut être quelques lignes plus tard ou après quelques itérations de boucle. Les boucles nécessitent généralement un état pour avoir un sens, et elles sont donc également intrinsèquement impératives.
Les variables et les boucles ne sont tout simplement pas une programmation fonctionnelle.
Sommaire
La programmation fonctionnellement contemporaine est un peu plus de style et une façon de penser utile qu'un paradigme. Une forte préférence pour les fonctions pures est dans cet état d'esprit, mais ce n'est qu'une petite partie en fait.
La plupart des langages répandus vous permettent d'utiliser certaines constructions fonctionnelles. Par exemple en Python, vous pouvez choisir 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))
Ces expressions fonctionnelles conviennent parfaitement à ce genre de problèmes et rendent simplement le code plus court (et plus court est bon ). Vous ne devriez pas remplacer inconsidérément le code impératif par eux, mais lorsqu'ils conviennent, ils sont presque toujours un meilleur choix.
item
variable mute dans la boucle.