Langages fonctionnels

La programmation fonctionnelle est un paradigme de programmation (une vision de la programmation) dans lequel un programme est construit en appliquant et en composant des fonctions ; le terme fonction est à prendre au sens mathématique du terme : f(x) = y.

Fonctions

Functions as "first class citizens"

Différents langages dits fonctionnels traduisent plus ou moins cette vision de manière stricte. Ils partagent tous au moins une caractéristique, c'est que les fonctions sont des "citoyennes de première classe", c'est à dire qu'elles font partie des types connus des langages fonctionnels. Une fonction peut donc être :
- nommée
- évaluée
- passée comme argument
- renvoyée comme résultat
- utilisée partout où une expression peut l'être.

Fonctions pures

Une fonction mathématique prend x en paramètre et renvoie y :
// isVoyelle('a') = true
// isVoyelle('r') = false
boolean isVoyelle(char c){ ... }
Une fonction transforme donc un type de donnée en un autre : char -- isVoyelle() --> boolean Et pour une valeur données de x, f(x) renvoie toujours la même valeur.
Dans les langages impératifs, à l'intérieur de la fonction isVoyelle(), on pourrait aller lire ou écrire dans un fichier, afficher une chaîne à l'écran, modifier une variable globale, tout en renvoyant toujours le même résultat. Une fonction peut avoir des effets de bord, son exécution a toujours lieu dans le cadre global de l'environnement d'exécution du programme.

C'est bien pratique mais ça ne donne pas la garantie qu'une fonction fera toujours exactement la même chose chaque fois qu'on l'appelle, ce qui peut avoir comme effet : Une fonction est dite pure si elle n'a pas d'effet de bord ; pour une valeur donnée d'un argument, la valeur du retour sera toujours la même.

En pratique, quand on programme, les fonctions ne sont pas pures, elles peuvent : Par exemple, la fonction test() suivante n'est pas pure.
class ExempleFonctionImpure {
    
    private static int i = 0;
    
    public static int test(int j){
        i += j;
        return i;
    }
    
}
En effet, test(1) va renvoyer 1 au premier appel, puis 2 au second appel etc.

Transparence référentielle

Propriété d'un langage (ou d'un programme) qui fait que toute variable, ainsi que tout appel à une fonction, peut être remplacée par sa valeur sans changer le comportement du programme.
(tiré de www.fil.univ-lille1.fr)

Pour satisfaire cette propriété,

Mémoïsation

Si une fonction est pure, pour un argument donné elle renvoie toujours la même valeur.
On peut donc fabriquer un cache : enregistrer dans un tableau toutes les valeurs possibles que peut prendre l'argument, avec la valeur de retour de la fonction. On dit qu'on peut la mémoïser.
Que l'on renvoie la valeur calculée ou la valeur stockée dans le cache, on aura le même résultat.
On dit que la fonction est mémoïsable.

En pratique, on ne peut pas le faire pour des types infinis (dont le cardinal de l'ensemble des valeurs du type est infini).

Curryfication

La notion de fonction pure est plus large que la notion mathématique de fonction ; en effet, une fonction pure peut avoir plusieurs arguments en entrée (et dans certains langages renvoyer plusieurs valeurs).
Mais on peut transformer une fonction prenant plusieurs arguments en une fonction prenant le premier argument et renvoyant une fonction prenant les arguments suivants. Ce procédé s'appelle la curryfication (le nom vient de Haskell Curry).

Exemple en PHP :
<?php
function uncurried_add($x, $y){
    return $x + $y;
}

// Avant PHP 7.4
function curried_add($x){
    return function($y) use($x) { return $x + $y; };
}

// Depuis PHP 7.4 ("arrow functions")
function curried_add2($x){
    return fn($y) => $x + $y;
}

echo "uncurried_add(3, 5) = " . uncurried_add(3, 5) . "\n";
echo "curried_add(3)(5) = " . curried_add(3)(5) . "\n";
echo "curried_add2(3)(5) = " . curried_add2(3)(5) . "\n";
(code source)
php curry.php
uncurried_add(3, 5) = 8
curried_add(3)(5) = 8
curried_add2(3)(5) = 8
Voir aussi un exemple en java.

Vocabulaire :
Une fonction d'ordre supérieur est une fonction qui prend en paramètre une fonction ou qui renvoie une fonction.

Monades

En pratique, on a besoin des effets de bords - sans eux, on ne pourrait même pas connaître le résultat de l'exécution d'un programme !
Comment faire tout en respectant l'intégrité référentielle ?
Les langages fonctionneles "purs" utilisent une construction nommée Monade.