Réflexions fonctionnelles avec Julia Language — Partie I
Explorer la programmation fonctionnelle avec Julia

Julia est considérée comme un langage typé dynamiquement à usage général qui prend en charge plusieurs paradigmes de programmation. À proprement parler, même si Julia n'est pas un langage de programmation fonctionnel (FP), il le prend en charge.
Alors, qu'est-ce qu'un langage de programmation fonctionnel "pur" ? Ce sont des langages conçus pour avoir des fonctions mathématiques qui utilisent des expressions conditionnelles et la récursivité pour effectuer des calculs. Ils utilisent des données immuables, une évaluation paresseuse et d'autres constructions pour « appliquer » le mode de programmation de la PF. Ces langues peuvent être assez concises et opiniâtres. Un bon exemple de cette classe de langage est Haskell.
Julia, cependant, est plus qu'heureuse de donner le pouvoir au programmeur, au lieu de placer des limites et des barrières sur le chemin pour forcer l'adhésion à tel ou tel paradigme.
Julia est-elle un bon langage pour programmer de manière fonctionnelle ? Je crois que oui. Alors pourquoi Julia est-elle bonne en programmation fonctionnelle ? Pour de nombreuses raisons, y compris la métaprogrammation, les objets de première classe, le système de type puissant, la répartition multiple et bien d'autres raisons.
FP gagne en popularité ces derniers temps. Les états d'objet mutables sont le nouveau code spaghetti et la concurrence ne fait qu'ajouter à la complexité. FP prend en charge la programmation parallèle et la concurrence, ce qui entraîne moins de bogues et un code propre. FP a à ses racines des concepts mathématiques solides et des idées d'un domaine mathématique émergent connu sous le nom de théorie des catégories.
Plongeons-nous directement et commençons à construire quelques concepts.
Programmation fonctionnelle en action
Disons que je suis intéressé à découvrir le cube de quelques nombres, je pourrais écrire :
3 * 3 * 3
2 * 2 * 2
cube(x) = *(x,x,x)
cube(x) = x * x * x
Maintenant, je suis intéressé par le calcul de quelques séries. Nous allons commencer par concevoir une fonction pour calculer la somme des entiers de a à b :
Maintenant, il ne serait pas exagéré de supposer qu'à un moment donné, je serais intéressé à calculer également la somme des cubes d'entiers dans une plage donnée. Dans ce cas, ma fonction pourrait ressembler à ceci :
Il n'est pas difficile de repérer le modèle de code présent dans les deux définitions de fonction ci-dessus. Un autre indice est le type de somme implicite dans le nom de la fonction elle-même. Ce dont nous avons besoin, c'est d'un autre niveau d'abstraction, afin de pouvoir calculer la somme de n'importe quelle série. Nous devons rendre le type de sum explicite et le passer comme argument à la fonction au lieu de coder en dur sur le corps de la fonction.
Avec la définition de fonction ci-dessus, nous rendons le type de fonction à sommer explicite en argument. J'ai annoté le paramètre "f" pour qu'il soit clair qu'il s'agit d'une fonction et non d'une autre valeur.
Maintenant, si je veux la somme des cubes de 1 à 10, je peux appeler ainsi :
Ou si je veux la somme des entiers de 1 à 10, je peux écrire :
Explorer les fonctions de Julia
Dans Julia, les fonctions sont des objets de première classe et peuvent être passées en arguments à d'autres fonctions. Cela ouvre la porte à des solutions encore plus élégantes avec des niveaux d'abstraction plus profonds.
Nous pouvons continuer à construire des abstractions au-dessus de l'abstraction. Nous pouvons également canaliser les fonctions ensemble dans des chaînes. On dit que Julia est un langage hautement composable. C'est ici qu'un peu de connaissance de la théorie des catégories peut vous aider à devenir un meilleur programmeur. La programmation fonctionnelle a des racines profondes dans les fondements mathématiques.
L'exemple ci-dessus montre des manières équivalentes de combiner et de composer des fonctions ensemble.
Les exemples ci-dessus montrent comment le passage de fonctions en tant qu'arguments peut nous aider à atteindre des niveaux d'abstraction plus profonds dans notre code. Mais il ne faut pas s'arrêter là. On peut créer des fonctions dont les valeurs de retour sont elles-mêmes des fonctions. Prenez le code suivant comme exemple. Considérons une fonction f qui renvoie la valeur moyenne entre x et f(x) . Nous appellerons cette fonction average_damp .
julia> average_damp(square)
#7 (generic function with 1 method)
Pour obtenir notre valeur d'humidité moyenne d'une fonction carrée au x=10 , nous appelons avec :
julia> average_damp(square)(10)
55.0

julia> dx = 0.00001;
julia> deriv(cube)(5)
75.00014999664018
Voici un exemple d'une telle fonction :
julia> withdraw(20)
80
julia>
julia> withdraw(20)
60
julia> withdraw(20)
40
julia> withdraw(20)
20
julia> withdraw(20)
0.0
julia>
Quoi qu'il en soit, plus à venir la prochaine fois…
Références : "Structure et interprétation des programmes informatiques", Abelson et Sussman