Programmation Fonctionnelle et Symbolique - techniques et méthodes



4.a Introduction

A l'instar de la programmation impérative, la programmation fonctionnelle ne saurait se réduire au simple énoncé de ses concepts; elle nécessite la connaissance d'un savoir-faire particulier. Dans cette partie nous abordons ces techniques de base, qui constituent en quelque sorte l'algorithmique de la programmation fonctionnelle.

La programmation fonctionnelle repose sur des outils mathématiques simples et bien connus : la notion de fonction, et le raisonnement par récurrence; nous verrons qu'ils permettent une grande rigueur dans l'écriture de programmes fonctionnels. nous pouvons par exemple prouver assez simplement l'équivalence de deux fonctions ; ce qui est relativement difficile à faire pour des programmes impératifs.

4.b Utilisation de la Récursivité (exemple des listes)

La programmation récursive apparait naturellement dès que l'on travaille sur des objets définis par récurrence; par exemple les listes de nombres : C'est ce que nous appellerons le «schéma de définition» du type de données «liste de nombres». Ce «schéma» sous-entend que : On utilise le «schéma» de la définition des listes pour définir des opérations sur les listes.

Exemples :

La démarche à suivre en général est la suivante, lorsqu'on veut (ou doit) écrire une fonction (reprenons l'appartenance):

  1. trouver les ensembles de départ et d'arrivée de la fonction (ça parait idiot mais pourtant c'est très important : cela permet de préciser la signification de la fonction.
    app : Nombre x Liste de Nombres --> Booleen
  2. rédiger en une phrase la spécification de la fonction (relation entre les données et le résultat)
    app[X,L] ssi est élément de L
  3. imaginer quelques exemples : les exemples triviaux et d'autres moins évidents : app[ 1 , () ] = faux app[ 1 , (1)] = vrai app[ 1 , (1 2 3) ] = vrai app[ 4 , (1 2 3) ] = faux app[ 3 , (1 2 3) ] = vrai
  4. essayer de construire un schéma de récurrence sur un des paramêtres. Ici la récurrence se fera sur les Listes de nombres. On doit donc commencer à écrire : app[ X , () ] = .... app[ X , cons[N,R] ] = .....app[ X , R] ....
  5. Essayer de remplir les trous. Le premier exemple nous amène à penser que la première ligne se complète en : app[ X , () ] = faux
    app[ X , cons[N,R] ] = .....app[ X , R] ....
    Pour la seconde ligne, on utilise encore les exemples, que l'on essaie d'identifier. Le second exemple s'identifie pour X=1, N=1, R=(2 3)
    app[ 1, cons[1,R] ] = .... app[1,R]...
    or nous savons que app[1,(2 3)]=faux. On comprend facilement que le résultat ne dépend pas de R à partir du moment où X=N. La 2ième ligne peut donc s'écrire : app[ X , cons[N,R] ] = si X=N alors vrai sinon ... app[X,R]... En raisonnant encore un peu sur les exemples, on voit que l'appartenance de X à R, si X est différent de R, équivaut à l'appartenance à la liste entière. D'où : app[ X , cons[N,R] ] = si X=N alors vrai sinon app[X,R] Ce qui s'écrit aussi : app[ X , cons[N,R] ] = (X=N) ou app[X,R] Remarque : cette méthode marche dans au moins 95% des cas !! On est donc prié de l'utiliser !!
Exercice : écrire une fonction qui indique combien il y a de nombres supérieurs à une certaine valeur dans une liste.

Solution

nbsup : Nombre x Liste de Nombres -> Liste de Nombres nbsup [ X , () ] = 0 nbsup [ X , cons[N,R] ] = si N < X alors nbsup[X,R] sinon nbsup[X,R]+1 Exercice : écrire une fonction qui renvoie la liste des entiers qui sont plus grands qu'une certaine valeur.

Exercice : La concaténation de deux listes : Liste x Liste --> Liste

conc[ () , L2 ] = L2 conc[ cons[N,R] , L2 ] = cons[ N , conc[R,L2] ] Remarque : Cette manière de définir la concaténation permet de prouver certaines propriétés plus ou moins évidentes.

Propriété à prouver: la liste vide est élément neutre de l'opération de concaténation

Preuve