Conf pf15 7

Télécharger au format pdf ou txt
Télécharger au format pdf ou txt
Vous êtes sur la page 1sur 44

Usages et perspectives de la programmation

fonctionnelle

Ph. Narbel
Université de Bordeaux, LaBRI

JDev 2015

version 1.2
Situation

La programmation fonctionnelle est à la mode...

Pourquoi donc ce changement de point de vue


des programmeurs et des créateurs de langages,
comment le justifier objectivement ?

Ph. Narbel Usages et perspectives de la programmation fonctionnelle 2


Programmation fonctionnelle à la mode ?
Langages fonctionnels... :
Langages “mainstream” : C#2.0-5.0, C++11/14, Java 8.
Langages outre Lisp : Javascript, Python, Smalltalk, Ruby,
OCaml/F#, Scala, Groovy, D, Erlang, Clojure, Go, Swift, etc.

Quelques livres très récents sur la programmation fonctionnelle :

Ph. Narbel Usages et perspectives de la programmation fonctionnelle 3


Être fonctionnel...

I. Comment définir
ce qu’est un langage fonctionnel,
et ce qu’est la programmation fonctionnelle ?

Ph. Narbel Usages et perspectives de la programmation fonctionnelle 4


Définir la programmation fonctionnelle

La programmation fonctionnelle : une programmation


basée sur les fonctions et leurs compositions, et
donc aussi basée sur la décomposition en fonctions.

Cet effet de composition/décomposition est la marque d’un


“paradigme de programmation”
(un moyen de modéliser, de construire des solutions).

Ceci dit, tous les langages possèdent la notion de fonction...


⇒ la programmation fonctionnelle consiste à exploiter
des fonctions avec des propriétés particulières,
propriétés qui leur donnent des moyens augmentés de bonne
composition/décomposition.

Ph. Narbel Usages et perspectives de la programmation fonctionnelle 5


Propriétés particulières des fonctions

Deux propriétés possibles des fonctions :


1 La “pureté” : les fonctions ont des résultats qui ne dépendent
strictement que de leurs arguments, sans autre effet externe.
⇒ cloisonnement, localisation, stabilité, déterminisme,
compositionnalité.
2 La “(citoyenneté) de première classe” : les fonctions ont un
statut de valeur.
⇒ flexibilité d’utilisation, compositionnalité.

La programmation fonctionnelle consiste à exploiter


l’une et/ou l’autre de ces deux propriétés.
Un langage fonctionnel : un langage qui permet et favorise
la programmation fonctionnelle.
Ph. Narbel Usages et perspectives de la programmation fonctionnelle 6
Pureté
Être une fonction pure, c’est donc engendrer des résultats
qui ne dépendent que des arguments, sans effet externe.
Par ex. voici une fonction pure et une fonction impure :

j = 4;

f(i) { g(i) {
return i + 4; j = i + j;
} return j ;
}

f ( 1 ) ; −−> 5 g ( 1 ) ; −−> 5
f ( 1 ) ; −−> 5 g ( 1 ) ; −−> 6

Par ex. log est pure ; random et print sont “impures” ;


Ph. Narbel Usages et perspectives de la programmation fonctionnelle 7
Première classe
Être de première classe, c’est donc avoir le même statut qu’une
valeur telle qu’un entier ou un caractère, c’est-à-dire :
1 Pouvoir être nommé, affecté (et typé) :
x := sin ;
2 Pouvoir être défini et créé à la demande :
x := ( function x −−> x + 1 ) ;
3 Pouvoir être passé en argument à une fonction :
f ( sin ) ;
4 Pouvoir être le résultat d’une fonction :
(f (3))(5);
5 Pouvoir être stocké dans une structure de données qlcq. :
array := {log , exp , tan } ;
Ph. Narbel Usages et perspectives de la programmation fonctionnelle 8
La notion de fermeture
La pureté et la première classe sont des propriétés
indépendantes l’une de l’autre.
Mais, pour être pure et/ou de première classe, une fonction doit
parfois être transformée en fermeture (closure), i.e. l’association
du code de la fonction avec un environment de définitions.
Par ex., la fonction suivante est transformée en fonction pure
et transportable dans un autre contexte, lorsqu’on lui associe
l’environnement { i=0, j=1, +=’code de +’ } :
i = 0; j = 1;
h(k) {
return i + j + k ;
}

⇒ La marque d’un langage fonctionnel : transformer


automatiquement les définitions de fonctions en fermetures.
Ph. Narbel Usages et perspectives de la programmation fonctionnelle 9
Être fonctionnel...

Les définitions précédentes indiquent que :

La pureté est surtout une discipline d’écriture des fonctions.

Les cinq caractéristiques de la première classe n’ont pas besoin


d’être toutes satisfaites pour améliorer le statut des fonctions.

Un langage fonctionnel n’a pas besoin de l’être exclusivement.

La pureté et la première classe peuvent être favorisés dans des


langages pour lesquels ils ne l’étaient pas initialement.

⇒ La programmation fonctionnelle est soluble dans l’eau


des autres paradigmes.

Ph. Narbel Usages et perspectives de la programmation fonctionnelle 10


De l’utilité d’être fonctionnel

II. Quelles sont les conséquences pratiques de la


pureté et de la première classe des fonctions
(en termes de développement de programmes) ?

Ph. Narbel Usages et perspectives de la programmation fonctionnelle 11


Conséquences de la pureté
La pureté induit la caractéristique principale suivante :
Indépendance au contexte de l’application d’une fonction :
cette application ne nécessite pas la prise en compte d’un
environnement, d’un état particulier.

Avec une conséquence importante :


Indépendance à l’ordre des applications dans les expressions
constituées de fonctions pures : chaque sous-expression est
évaluable n’importe quand, et remplaçable par son résultat
n’importe quand (cf. transparence référentielle).

f ( g (3 , h ( ” i c i ” , 9 . 1 ) , l o g (1) , r ( ’ a ’ , ’ c ’ ) ) , 10)
f ( g (3 , h ( ” i c i ” , 9 . 1 ) , 0 , r ( ’ a ’ , ’ c ’ ) ) , 10)

⇒ Stabilité lors de la composition des fonctions


(cf. définition du paradigme fonctionnel).
Ph. Narbel Usages et perspectives de la programmation fonctionnelle 12
Conséquences de la pureté

L’indépendance au contexte et à l’ordre d’évaluation :

a. Formalisations facilitées de la notion de fonction (pas d’états)


Une application de fonction peut devenir une règle de réécriture.
⇒ λ-calculs, preuves de cohérence, confluence, terminaison, etc.

b. Typages plus complets et plus représentatifs du comportement


des fonctions : toute sous-expression renvoie un résultat (typable).
Ce typage peut s’ajouter aux formalisations ci-dessus.

c. Parallélisation naturelle : indépendance directe des calculs.

Ph. Narbel Usages et perspectives de la programmation fonctionnelle 13


Conséquences de la pureté

d. Lisibilité, maintenabilité améliorées : cloisonnement, localisation,


stabilité, déterminisme des calculs. Par exemple (rappel) :
j = 4;
f(i) {
g(i) {
return i + 4;
j = i + j;
}
return j ;
}
Et donc certes, f(1)-f(1)==0, mais quoi de g(1)-g(1) ?...
Et donc certes, f(1)+f(1) = 2*f(1), mais quoi de g(1)+g(1) ?...

e. Tests facilités : tests en boı̂te noire immédiats, constructions


simplifiées d’environnements spécifiques de tests (i.e. fixturing,
stubbing, mocking, dummying simplifiés).

Ph. Narbel Usages et perspectives de la programmation fonctionnelle 14


Conséquences de la pureté
f. Optimisations possibles :

i. Mémorisation de valeurs : les résultats des fonctions étant


déterministes, ils peuvent être stockés, mis en cache (caching).

ii. Contrôle de l’évaluation (cf. nécessité, paresse), par ex. :

f(x , y , z) {
i f ( x > 0) y e l s e z ;
}

f ( 1 , 1 , exp ( 1 0 0 0 0 0 0 0 0 0 ) ) ;
−−> i f ( 1 > 0 ) 1 e l s e exp ( 1 0 0 0 0 0 0 0 0 0 ) −−> 1 ;

f ( 1 , 1 , 1/0 ) ;
−−> i f ( 1 > 0 ) 1 e l s e 1/0 −−> 1 ;

Ph. Narbel Usages et perspectives de la programmation fonctionnelle 15


Conséquences de la pureté

Néanmoins, la pureté rend certaines choses compliquées


(mais non pas impossibles), par exemple :
La gestion des structures de données (cf. la persistance).
La gestion de la mémoire explicite (cf. les ramasses-miettes).
La définition des entrées/sorties, du traitement d’erreurs,
(cf. les monades).

Il est possible de ne programmer qu’avec des fonctions pures


(par ex. Haskell est même un langage qui l’impose).

Ph. Narbel Usages et perspectives de la programmation fonctionnelle 16


Indiquer explicitement la pureté

Certains langages permettent d’annoter les fonctions


pour indiquer explicitement qu’elles sont pures.
Par exemple, en C# :

[ Pure ]
bool F ( i n t i ) {
return ( i + 4) > 0 ;
}

Contract . Requires ( F ( 0 ) ) ;

Et par exemple, dans la documentation officielle de C# :


“Toutes les méthodes appelées dans un contrat doivent être pures ;
autrement dit, elles ne doivent pas mettre à jour un état préexistant.”

Ph. Narbel Usages et perspectives de la programmation fonctionnelle 17


Conséquences de la première classe

La première classe des fonctions est déterminée par (rappel) :

0 Pouvoir être nommé, affecté (et typé).


1 Pouvoir être défini et créé à la demande.
2 Pouvoir être passé en argument à une fonction.
3 Pouvoir être le résultat d’une fonction.
4 Pouvoir être stocké dans une structure de données qlcq..

⇒ Nouveaux moyens de composition des fonctions


(cf. définition du paradigme fonctionnel).

Ph. Narbel Usages et perspectives de la programmation fonctionnelle 18


Conséquences de la première classe
Pouvoir être passée en argument à une fonction induit la
possibilité de généralisation/abstraction fonctionnelle
(cf. aussi “programmation d’ordre supérieur”) :

two_times_exp ( x ) {
r e t u r n exp ( exp ( x ) ) ;
};

two_times_f ( x , f ) {
return f ( f (x ) ) ;
};

⇒ Tout “morceau de code” dans une fonction est remplaçable


par une abstraction, i.e. un paramètre fonctionnel.
(c’est l’effet principal de la première classe pour les fonctions).
Ph. Narbel Usages et perspectives de la programmation fonctionnelle 19
Conséquences de la première classe
Autre exemple de généralisation fonctionnelle (en Javascript)
(implémentation d’un processus itératif particulier) :
f u n c t i o n iterateUntil ( init ) {
v a r ret = [ ] ;
v a r result = init ∗ 1 0 0 0 ;
w h i l e ( result > 2 0 0 0 ) {
ret . push ( result ) ;
result = result ∗ 1 0 0 0 ) ;
}
r e t u r n ret ;
};

f u n c t i o n iterateUntil ( f u n , c h e c k , init ) {
v a r ret = [ ] ;
v a r result = f u n ( init ) ;
w h i l e ( c h e c k ( result ) ) {
ret . push ( result ) ;
result = f u n ( result ) ;
}
r e t u r n ret ;
};
(dû à M. Fogus)
Ph. Narbel Usages et perspectives de la programmation fonctionnelle 20
Conséquences de la première classe

La généralisation fonctionnelle dans un cadre statiquement


typé (e.g. Java, C++, C#) nécessite des types de fonctions
(en fait, les autres propriétés de la première classe aussi) :

f l o a t two_times_exp ( f l o a t x ) {
r e t u r n exp ( exp ( x ) ) ;
}

f l o a t two_times_f ( f l o a t x , f u n t f l o a t f l o a t f ) {
return f(f(x ) ) ;
}

Ph. Narbel Usages et perspectives de la programmation fonctionnelle 21


Première classe et généricité

La généralisation fonctionnelle dans un cadre statiquement


typé nécessite souvent des types génériques de fonctions
(car elle induit des fonctions avec des codes moins spécifiques) :

f l o a t two_times_f ( f l o a t x , f u n t f l o a t f l o a t f ) {
return f(f(x ) ) ;
}

T1 two_times_f ( T1 x , f u n t ( T1 , T1 ) f ) {
return f(f(x ) ) ;
}

Ph. Narbel Usages et perspectives de la programmation fonctionnelle 22


Première classe et généricité
⇒ Définitions de types génériques de fonctions en C#
sous forme de types de délégués (cf. .NET System) :
Func ( TResult ) Delegate
Func ( T1 , TResult ) Delegate
Func ( T1 , T2 , TResult ) Delegate
...
Func ( T1 , T2 , T3 , T4 , T5 , T6 , T7 , T8 , T9 , . . . . ,
T15 , T16 , TResult ) Delegate
Action Delegate
Action ( T1 ) Delegate
Action ( T1 , T2 ) Delegate
...
Action ( T1 , T2 , T3 , T4 , T5 , T6 , T7 , T8 , T9 , . . . . , T15 , T16 ) Delegate

L’exemple précédent en C# :
T1 TwoTimesFun<T1>( T1 x , Func<T1 , T1> f ) {
return f(f(x ) ) ;
}

TwoTimesFun ( 3 . 0 , Math . Exp ) ) ; // c a l l


Ph. Narbel Usages et perspectives de la programmation fonctionnelle 23
Première classe et généricité
Extrait de la documentation de .NET System... :

Ph. Narbel Usages et perspectives de la programmation fonctionnelle 24


Première classe et généricité
⇒ Définitions des types génériques de fonctions en Java 8
sous forme d’interfaces fonctionnelles, i.e. interfaces avec une
seule méthode abstraite (cf. java.util.function)
(mais donc sans surcharge de nommage comme en C#...) :
BiConsumer<T , U>, BiFunction<T , U , R>, BinaryOperator<T>, BiPredicate<T , U>,
BooleanSupplier , Consumer<T>, DoubleBinaryOperator , DoubleConsumer ,
DoubleFunction<R>, DoublePredicate , DoubleSupplier , DoubleToIntFunction ,
DoubleToLongFunction , DoubleUnaryOperator , Function<T , R>, IntBinaryOperator ,
IntConsumer , IntFunction<R>, IntPredicate , IntSupplier , IntToDoubleFunction ,
IntToLongFunction , IntUnaryOperator , LongBinaryOperator , LongConsumer ,
LongFunction<R>, LongPredicate , LongSupplier , LongToDoubleFunction ,
LongToIntFunction , LongUnaryOperator , ObjDoubleConsumer<T>, ObjIntConsumer<T>,
ObjLongConsumer<T>, Predicate<T>, Supplier<T>, ToDoubleBiFunction<T , U>,
ToDoubleFunction<T>, ToIntBiFunction<T , U>, ToIntFunction<T>, ToLongBiFunction<T , U>,
ToLongFunction<T>, UnaryOperator<T>

L’exemple précédent en Java :


<T1> T1 twoTimesFun ( T1 x , F u n c t i o n <T1 , T1> f ) {
r e t u r n f . apply ( f . apply ( x ) ) ;
}

twoTimesFun ( 3 . 0 , x −> Math . e x p ( x ) ) ; // c a l l


Ph. Narbel Usages et perspectives de la programmation fonctionnelle 25
Première classe et généricité
Extrait de la documentation de l’API Java SE8...
(java.util.function) :

Ph. Narbel Usages et perspectives de la programmation fonctionnelle 26


Première classe et généricité
Remarque : l’exploitation des propriétés de la première classe
peut être allégée par des mécanismes d’inférence de type :
Langages avec inférence complète des types génériques fonctionnels :
two_times_f ( x , f ) = f ( f ( x ) ) ; ; // H a s k e l l
−−> t w o t i m e s f : ( t , ( t −> t ) ) −> t

let two_times_f ( x , f ) = f ( f ( x ) ) ; ; // OCaml


−−> v a l t w o t i m e s f : ’ a ∗ ( ’ a −> ’ a ) −> ’ a

Langages avec plus ou moins d’inférence de type :


a u t o f = [ ] ( double x ) { return exp ( exp ( x ) ) ; } ; // C++
d e f f [ T ] = ( ( x : T , f : T=>T ) => f ( f ( x ) ) ) // S c a l a

C# offre un “var”, mais trop faible pour les types de fonctions ;


Java n’a encore que quelques zestes d’inférence de type.
Ph. Narbel Usages et perspectives de la programmation fonctionnelle 27
Conséquences de la première classe
Pouvoir être défini et créé à la demande est réalisé par
les “fonctions anonymes” (par défaut, les valeurs sont sans nom),
aussi appelées lambdas ou fermetures :
x −> x + 1 // J a v a
x => x + 1 // C#
[ ] ( int x ) −> { return x + 1 ; } // C++
function ( x ) { return x + 1 } // J a v a s c r i p t
lambda x : x + 1 // Python
\x −> x + 1 // H a s k e l l
[ :x | x + 1 ] // S m a l l t a l k
x => x + 1 // S c a l a
fun x −> x + 1 // OCaml

Les fonctions anonymes servent à “nourrir” à la volée


les variables, les données, les paramètres fonctionnels, par ex. :
two_times_f ( 1 , ( x −> x + 1 ) ) −−> 3
Ph. Narbel Usages et perspectives de la programmation fonctionnelle 28
Conséquences de la première classe

La généralisation fonctionnelle + fonctions anonymes :

⇒ intégration facile de nouveau code dans code existant.


⇒ flexibilité du code, maintenabilité, extensibilité.
C’est une des principales utilisations des fonctions de première
classe dans la programmation de tous les jours.

Exemple principal d’application : la généralisation des


traitements itératifs sur les structures de données par trois types
de fonctions appelées maps, reduces/folds, et filtres :

Ph. Narbel Usages et perspectives de la programmation fonctionnelle 29


Conséquences de la première classe
Généralisation fonctionnelle des traitements itératifs :
a. Les “maps” : transformations uniformes de structures
(cf. “itérateurs internes”).

list_map ( list , f ) {
i f ( isEmpty list )
r e t u r n emptyList ;
else
r e t u r n addFirst ( f ( getFirst ( list ) ) ,
list_map ( getTail ( list ) , f ) ) ;
}

list_map ( [ 1 , 2 , 3 , 4 ] , ( x −> x + 1 ) ) −−> [ 2 , 3 , 4 , 5 ]


list_map ( [ 1 , 2 , 3 , 4 ] , ( x −> x ∗ 2 ) ) −−> [ 2 , 4 , 6 , 8 ]

Ph. Narbel Usages et perspectives de la programmation fonctionnelle 30


Conséquences de la première classe

Généralisation fonctionnelle des traitements itératifs :

b. Les “reduces” (ou “folds”) : calculs de valeurs à partir d’un


parcours sur tous les éléments d’une structure.

list_reduce ( list , f , startvalue ) { . . . }

list_reduce ( [ 1 , 2 , 3 , 4 ] , ( ( x , y ) −> x + y ) , 0 ) −−> 10


list_reduce ( [ 1 , 2 , 3 , 4 ] , ( ( x , y ) −> x + 1 ) , 0 ) −−> 4

Ph. Narbel Usages et perspectives de la programmation fonctionnelle 31


Conséquences de la première classe

Généralisation fonctionnelle des traitements itératifs :

c. Les filtres : extractions des éléments d’une structure qui vérifient


un prédicat.

list_filter ( list , p r e d ) { . . . }

list_filter ( [ 1 , 2 , 3 , 4 ] , ( x −> x > 2 ) ) −−> [ 3 , 4 ]


list_filter ( [ 1 , 2 , 3 , 4 ] , ( x −> x < 2 ) ) −−> [ 1 ]

Ph. Narbel Usages et perspectives de la programmation fonctionnelle 32


Conséquences de la première classe

⇒ La plupart des langages fonctionnels proposent des


maps/reduces/filtres dans leur bibliothèques
(en une sorte de “couteau suisse” des structures de données) :
map , reduce , filter // Java
Select , Aggregate , Where // C#
map , reduce , filter // Javascript
map , fold , filter // OCaml
collect : , reduce : , select : // Smalltalk

Et souvent avec beaucoup de dérivés,


par exemple dans Underscore.js :
each , reduceRight , find , where , findWhere , reject , every ,
some , contains , invoke , pluck , max , min , sortBy , groupBy ,
indexBy , countBy , shuffle , sample , toArray , size , partition .

Ph. Narbel Usages et perspectives de la programmation fonctionnelle 33


Conséquences de la première classe
Les ensembles de fonctions maps/reduces/filters sont aussi
utilisés pour énoncer des compositions de traitements à la
manière de requêtes bases de données :

En C# (cf. LINQ, Language Integrated Query) :


IEnumerable<i n t > q = giraffes
. Select ( g => g . Age ∗ 3 ) ;
. Where ( g => g . Age > 2 )
. OrderByDescending ( g => g . Age )

En Java 8 (java.util.stream.ReferencePipeline) :
Stream<Integer> q = giraffes . stream ( )
. map ( g −> g . age ∗ 3 ) ;
. filter ( g −> g . age > 2 )
. sorted ( ( g1 , g2 ) −> Integer . compare ( g1 . age , g2 . age ) )

Ph. Narbel Usages et perspectives de la programmation fonctionnelle 34


Conséquences de la première classe
Pouvoir être le résultat d’une fonction permet :
Adaptations de fonctions, définitions d’appels particuliers
(cf. fonctions “around”, et aussi “décorateurs” en Python) :
list_map_scaling ( k ) {
return function (l) {
return l i s t m a p (l , function (n) {
return (n ∗ k ) ;
});
};}

Applications partielles (cf. fonctions “curryfiées”) :


curried_add ( a ) {
return function (b) {
return a + b ;
};}

v a r add5 = curried_add ( 5 ) ;
add5 ( 3 ) −−> 8
Ph. Narbel Usages et perspectives de la programmation fonctionnelle 35
Conséquences de la première classe
Pouvoir être stocké dans une structure de données permet :
Gestion d’ensembles de fonctions, structurés en listes, tables, arbres,
graphes, etc. (cf. “modularité dynamique”).

graphic_actions := [
( ’ f1 ’ , ( x , y) −> action1 ( x , y ) ) ,
( ’ f2 ’ , ( x , y) −> action2 ( x , y ) ) ,
( ’ f3 ’ , ( x , y) −> action3 ( x , y ) ) ,
...
];

Passages d’arguments sous forme d’ensembles de fonctions


(au lieu de simples fonctions) :
graphic_environment ( graphic_actions ) ;

⇒ Programmation orientée-données (data-driven).


Ph. Narbel Usages et perspectives de la programmation fonctionnelle 36
Conséquences de la première classe
Certaines techniques de programmation fonctionnelle utilisent
la pureté + la première classe :

Les techniques “mapreduce” : traitements itérés généralisés à base


de fonctions pures permettant une parallélisation facile.
r e d u c e ( map ( list , purefun1 ) , purefun2 )

Le contrôle de l’évaluation par émulation fonctionnelle :


expressions pures encapsulées dans des fonctions sans paramètres
(évaluation à la demande par appel de ces fonctions).

expression function() { expression }

Par exemple :
benchMarkAndTest ( f u n c t i o n ( ) { exp ( 1 0 0 0 0 0 0 0 0 0 ) ; } )

Ph. Narbel Usages et perspectives de la programmation fonctionnelle 37


Programmation fonctionnelle et objet

III. Pourquoi le paradigme fonctionnel est-il


désormais souvent intégré au paradigme objet ?

Ph. Narbel Usages et perspectives de la programmation fonctionnelle 38


Programmation fonctionnelle et objet

Les langages objets principaux Java, C++ et C# sont


basés sur les “classes-modules” (“classes as modules”).
Une des idées fortes du développement en programmation objet :
les actions de maintenance, d’extension, d’adaptation
peuvent passer par l’héritage et la composition de classes
(on évite ainsi toute modification du code existant).
⇒ Parfois trop lourd... ! Prolifération de classes... !
Par ex. en Java < 8, pour contrer cet effet : utilisation de
classes internes anonymes.
La programmation fonctionnelle est une solution à ce
problème.

Ph. Narbel Usages et perspectives de la programmation fonctionnelle 39


Un design pattern classique : la Stratégie
Par ex. le design pattern “Stratégie” consiste à “laisser un
algorithme varier indépendamment des clients qui l’utilisent”.
Tactique objet d’implémentation : composition d’objets.
c l a s s Context {
Strategy s t r a t e g y ;
Context ( Strategy s ) { s t r a t e g y = s ; }
f l o a t context ( f l o a t x ) {
return strategy . algorithm (x );
}
}

Composition c = new Composition ( i n s t a n c i a t e d S t r a t e g y ) ;

(issu du GoF)
Ph. Narbel Usages et perspectives de la programmation fonctionnelle 40
Un design pattern classique : la Stratégie
Tactique fonctionnelle d’implémentation : passage de
fonctions en paramètre (cf. première classe) (en Java 8) :
c l a s s Context {
Function<Float , Float> a l g o r i t h m ;
// p r e d e f i n e d f u n c t i o n a l i n t e r f a c e
Context ( Function<Float , Float> a ) { a l g o r i t h m = a ; }
f l o a t context ( f l o a t x ) {
return algorithm . apply (x ) ;
}
}

Context c = new Context ( x −> x + 1 ) ;

Ph. Narbel Usages et perspectives de la programmation fonctionnelle 41


Autres design patterns...
D’autres design patterns, e.g. Commande, Observateur, Visiteur
peuvent bénéficier de la première classe des fonctions :

⇒ La granularité fine de la programmation fonctionnelle peut


agir efficacement sur la granularité générale modulaire.
Ph. Narbel Usages et perspectives de la programmation fonctionnelle 42
Intégrer la programmation fonctionnelle
Règle : un langage qui intègre la première classe des
fonctions doit faciliter la programmation fonctionnelle et
la promouvoir (cf. déf. de langage fonctionnel).
Par exemple en Java 8 , l’intégration de la programmation
fonctionnelle a induit des modifications de la notion d’interface :
a. Les types de fonctions sont représentés par des interfaces
fonctionnelles, instanciables par des lambdas.
b. Les interfaces avec implémentations de méthodes par défaut :
⇒ Interfaces fonctionnelles plus complexes.
⇒ L’API Java 8 compatible ascendante avec les API Java < 8.
Par ex., le “couteau suisse” sur les structures de données :
⇒ Dans Collection<E>, ajoûts suivants (par rapport à Java 7) :
d e f a u l t b o o l e a n removeIf ( Predicate <? s u p e r E> filter )
⇒ Dans Iterable<E>, ajoûts suivants :
d e f a u l t v o i d forEach ( Consumer <? s u p e r T> action )
Ph. Narbel Usages et perspectives de la programmation fonctionnelle 43
Ce qu’on peut retenir ?

La programmation fonctionnelle est bonne pour le


développement de programmes : pureté et première classe
induisent une part de stabilité, déterminisme, testabilité,
cloisonnement, fluidité d’utilisation, compositionalité,
généralisation, extensibilité, etc.
La programmation fonctionnelle est bonne pour
l’objet-modulaire : elle met un peu d’huile dans les rouages,
et amoindrit parfois la complexité des architectures.
La programmation fonctionnelle est soluble :
pureté et première classe des fonctions peuvent être considérées,
incluses et facilitées dans n’importe quel langage.

Ph. Narbel Usages et perspectives de la programmation fonctionnelle 44

Vous aimerez peut-être aussi