Scala : programmation fonctionnelle

49
SCALA PROGRAMMATION FONCTIONNELLE CONCEPTS ET MISE EN OEUVRE Dr Mustapha Michrafy M. MICHRAFY Contact de l’auteur : [email protected] [email protected] 1

Transcript of Scala : programmation fonctionnelle

Page 1: Scala : programmation fonctionnelle

SCALAPROGRAMMATION FONCTIONNELLE CONCEPTS ET MISE EN ŒUVRE

Dr Mustapha Michrafy

M. MICHRAFY

Contact de l’auteur :[email protected]

[email protected]

Page 2: Scala : programmation fonctionnelle

Contexte

Cette étude a été présentée dans le cadre du séminaire « Data Science principes, outils et applications » au laboratoire Cermsem.

[email protected]. MICHRAFY 2

Page 3: Scala : programmation fonctionnelle

Plan• Objectif• Prérequis• Tout est fonction• Fonction pure • Fonction anonyme• Fonction d’ordre supérieur• Clôture• Fonction partielle• Récursivité• Curryfication

[email protected]. MICHRAFY 3

Page 4: Scala : programmation fonctionnelle

Objectif

Cette étude vise à présenter laprogrammation fonctionnelle sous Scala.

[email protected]. MICHRAFY 4

Page 5: Scala : programmation fonctionnelle

Prérequis• Connaissance du langage Scala• Notion de récursivité

[email protected]. MICHRAFY 5

Page 6: Scala : programmation fonctionnelle

Tout est fonction• Dans le paradigme fonctionnel, tout est fonction.• Un traitement complexe est composé de plusieurs

fonctions

[email protected]. MICHRAFY 6

Page 7: Scala : programmation fonctionnelle

Fonction en scala• En scala, une fonction est un objet qui peut être affecté à

une variable.• La définition d’une fonction peut être effectuée n’importe

où dans un fichier source.• La définition d’une fonction en scala nécessite l’utilisation

du mot clé def suivi du nom de la fonction, de zéro, d’un ou de plusieurs arguments d’entrée, le type de retour et le corps de la fonction

def add(x:Int, y:Int) : Int = {return x+y;}

Nom de la fonctionArguments d’entrée

Valeur de retourCorps de la fonction

[email protected]. MICHRAFY 7

Page 8: Scala : programmation fonctionnelle

Appel à une fonction en scala• L’appel d’une fonction se fait via son nom, suivi par les

arguments d’entrée entre parenthèses et séparés par un virgule.• Si la fonction ne demande pas d’argument d’entrée, l’appel se

fait seulement avec son nom, et optionnellement suivi par une paire de parenthèses vides ().

def add(x:Int, y:Int) : Int = {return x+y;}

Add(8,17) Appel de la fonction add

Définition de la fonction add

def hello() =

hello()

hello

Définition de la fonction hello

Appel de la fonction hello avec ()

Appel de la fonction hello sans ()

[email protected]. MICHRAFY 8

Page 9: Scala : programmation fonctionnelle

Fonction pure• Une fonction pure est une fonction qui respecte les 2

critères suivants :1. La fonction est déterministe, c-à-d renvoie toujours la même

valeur pour les mêmes arguments2. La fonction ne retourne que la valeur résultat, sans effet de bord.

• Les fonctions arithmétiques sont des fonctions pures

• Les fonctions mathématiques sont des fonctions pures

• Toute fonction à effet de bord n’est pas une foncti on pure

[email protected]. MICHRAFY 9

Page 10: Scala : programmation fonctionnelle

Fonctions mathématiques

Fonction Sin def sin(x:Double) : Double = Math.sin(x)

Fonction

identitédef identite(x:Double) : Double = x

Fonction

constantedef constante(x:Double) : Double = 7

Fonction

affinedef affine(x:Double) : Double = 3*x+5

Formulation syntaxique en scala

Nom de la fonction

Argument d’entré et son type

Expression de retour

Type de retour

[email protected]. MICHRAFY 10

Page 11: Scala : programmation fonctionnelle

Fonctions mathématiques scalascalascalascala> defdefdefdef sin(x : Double) : Double sin(x : Double) : Double sin(x : Double) : Double sin(x : Double) : Double = = = = Math.sinMath.sinMath.sinMath.sin(x)(x)(x)(x)

sin: (x: Double)Doublescalascalascalascala> sin(80)

res0: Double = -0.9938886539233752scalascalascalascala> def identite(x : Double) : Double = {return x;}

identite: (x: Double)Doublescalascalascalascala> identite(80)

res1: Double = 80.0scalascalascalascala> def constante(x : Double) : Double = 13

constante: (x: Double)Doublescalascalascalascala> constante(80)

res2: Double = 13.0scalascalascalascala> def affine(x : Double) : Double = 3*x + 5

affine: (x : Double)Doublescalascalascalascala> affine(80)

res3: Double = 245.0

[email protected]. MICHRAFY 11

Signature de la fonction

Page 12: Scala : programmation fonctionnelle

Fonction anonyme : principe• Une fonction anonyme en scala permet de définir une

fonction sans déclarer le nom de la fonction

• Une fonction anonyme est similaire à une lambda expression et permet de créer des fonctions à la volée

• Une fonction anonyme peut être utilisée :• pour initialiser une variable• comme argument d’une fonction• comme valeur de retour d’une fonction

[email protected]. MICHRAFY 12

Page 13: Scala : programmation fonctionnelle

Fonction anonyme : syntaxe• La syntaxe d’une fonction anonyme commence par une

liste d’arguments séparés par des virgules et entourés par des parenthèses. Observons l’exemple suivant :

scala> val add = (x:Int, y:Int) => x+y

La fonction anonymeAdd est initialisé par la fonction anonyme

[email protected]. MICHRAFY 13

Page 14: Scala : programmation fonctionnelle

Fonction anonyme : invocation

scala> val add = (x:Int, y:Int) => x+yadd: (Int, Int) => Int = <function2>

scala> add(7,8)res4: Int = 15

Invocation de la fonction anonyme

Définition de la fonction anonyme

Comment les fonctions anonymes sont-elles créées ?

Pourquoi <fonction2>?

[email protected]. MICHRAFY 14

Page 15: Scala : programmation fonctionnelle

Fonction anonyme : constructionscala> val add1:(Int, Int) => Int = (x:Int, y:Int) => x+y

add1: (Int, Int) => Int = <function2>= <function2>= <function2>= <function2>scala> add1(1,10)

res0: Int = 11scala> val add2: Function2[Function2[Function2[Function2[Int,Int,IntInt,Int,IntInt,Int,IntInt,Int,Int] ] ] ] = ((((x:Intx:Intx:Intx:Int, y:Int) => , y:Int) => , y:Int) => , y:Int) => x+yx+yx+yx+y

add2: (Int, Int) => Int = <function2><function2><function2><function2>scala> add2.applyapplyapplyapply(1,10)

res1: Int = 11

• Une fonction anonyme est instanciée par un objet de type « fonction »

• L’objet étend le type FonctionNFonctionNFonctionNFonctionN, N désignant l’arité de la fonction anonymes

• L ’objet FonctionN dispose d’une méthode « apply »

[email protected]. MICHRAFY 15

Page 16: Scala : programmation fonctionnelle

Fonction comme variable• En scala et dans le paradigme fonctionnel en général,

nous pouvons utiliser une fonction comme variable.

scala> val valImpair = (n:Int) => 2*n + 1valImpair: Int => Int = <function1>

scala> valImpair(10)res3: Int = 21

La variable valImpair a pour valeur la fonction <function1>

[email protected]. MICHRAFY 16

Page 17: Scala : programmation fonctionnelle

Fonction comme argument : déclaration

• Il est aussi possible de définir une fonction qui prend en entrée une fonction

• Ce principe est similaire au pointeur de fonction en C/C++ ou aux interfaces fonctionnelles en Java

• Il suffit de déclarer la signature de la fonction

defdefdefdef nomFonctionnomFonctionnomFonctionnomFonction(fctfctfctfct:([:([:([:([paramsparamsparamsparams]) => ]) => ]) => ]) => typeRetourtypeRetourtypeRetourtypeRetour, arg:type, ...) : typeRetourtypeRetourtypeRetourtypeRetour = {....}

Fonction comme argument d’une autre fonction

[email protected]. MICHRAFY 17

Page 18: Scala : programmation fonctionnelle

Fonction comme argument : exemplescala> scala> scala> scala> def operationoperationoperationoperation(op:(op:(op:(op:(Int,IntInt,IntInt,IntInt,Int)=>Int)=>Int)=>Int)=>Int, x:Int,y:Int) : Int = op(x,y)

operation: (op: (Int, Int) => Int, x: Int, y: Int)Int

scala> scala> scala> scala> def addaddaddadd(x:Int,y:Int):Int = x+yadd: (x: Int, y: Int)Int

scala> scala> scala> scala> def produitproduitproduitproduit(x:Int, y:Int):Int = x*yproduit: (x: Int, y: Int)Int

scala> scala> scala> scala> operationoperationoperationoperation(addaddaddadd,7,8)res4: Int = 15

scala> scala> scala> scala> operationoperationoperationoperation(produit,produit,produit,produit,7,8)res5: Int = 56

operation a la fonction op comme argument

Les fonctions add et produit ont la même signature que op

Appel de la fonction operation avec addcomme paramètre

Appel à la fonction operation avec produit comme paramètre

[email protected]. MICHRAFY 18

Page 19: Scala : programmation fonctionnelle

Fonction comme valeur de retour• Il est aussi possible d’avoir une fonction comme valeur de

retour d’une fonction

• Dans ce cas, la fonction doit avoir une valeur de retour de type fonction ou une fonction anonyme

• Il préférable d’utiliser les accolades pour la lisibilité.

[email protected]. MICHRAFY 19

Page 20: Scala : programmation fonctionnelle

Fonction comme valeur de retourscala> scala> scala> scala> def fabriqueFctAffinefabriqueFctAffinefabriqueFctAffinefabriqueFctAffine(a:Int ,b:Int) : (Int)=>Int

| = {(x:Int)=> a*x+b} fabriqueFctAffine: (a: Int, b: Int)Int => Int

scalascalascalascala> def diag = fabriqueFctAffinefabriqueFctAffinefabriqueFctAffinefabriqueFctAffine(2,3) diag: Int => Int

scalascalascalascala> diag(1) res0: Int = 5

[email protected]. MICHRAFY 20

La fonction fabriqueFctAffine renvoie une fonction affine ayant pour coefficients les arguments a et b fournis en entrée

diag est la fonction définit par : �� → ��� → 2� � 3

Signature de la fonction fabriqueFctAffine

Signature de la fonction diag

Page 21: Scala : programmation fonctionnelle

La fonction composée• La fonction composée (notée o en mathématique) est la

fonction qui prend en entrée deux fonctions et retourne la fonction composée des deux

• Soient deux fonctions F et G, pour définir FoG, il est nécessaire que l’ensemble {G(x), x dans Domaine(G)} inclut dans Domaine(F) :

∶ �1 → 2, � ∶ �2 → 2��������� ∶ �1 ∁�2

[email protected]. MICHRAFY 21

Page 22: Scala : programmation fonctionnelle

La fonction composée

[email protected]. MICHRAFY 22

F(x) = x*x

G(x) = x+1

FoG(x) = F(G(x))

= F(x + 1) = x*x+1

Formulation mathématique

Opérateur o

scala> scala> scala> scala> def FFFF(x : Int) : Int = x*xF: (x: Int)Intscala> scala> scala> scala> def GGGG(x : Int) : Int = x + 1G: (x: Int)Int

scala> scala> scala> scala> defdefdefdef compose(Fcompose(Fcompose(Fcompose(F:(Int)=>(Int), G:(Int)=>(Int)) : (Int)=>(Int) = (Int)=>F(G(Int))compose: (F: Int => Int, G: Int => Int)Int => Intcompose: (F: Int => Int, G: Int => Int)Int => Intcompose: (F: Int => Int, G: Int => Int)Int => Intcompose: (F: Int => Int, G: Int => Int)Int => Int

Compose(F,G) = FoG

Page 23: Scala : programmation fonctionnelle

Clôture : principe• Une clôture ou fermeture est une fonction dont la valeur

de retour dépend de la valeur d'une ou plusieurs variables déclarées à l'extérieur de cette fonction

• Les clôtures permettent d’encapsuler une partie du contexte d’exécution dans une fonction

[email protected]. MICHRAFY 23

Page 24: Scala : programmation fonctionnelle

Clôture : exemplescala> val a = 2

a: Int = 2scala> val b = 3

b: Int = 3scala> def affine(x:Int,y:Int):Int = aaaa*x + bbbb

affine: (x: Int, y: Int)Intscala> affine(1,1)

res7: Int = 5

a, b sont déclarées en dehors de la portée de la fonction affine

[email protected]. MICHRAFY 24

Page 25: Scala : programmation fonctionnelle

Fonction partielle• En figeant les valeurs d’un sous-ensemble des

paramètres d’une fonction connue, on obtient une fonction partielle (projection, spécialisation)

scala> scala> scala> scala> def produit(x:Int, y:Int):Int = x*yproduit: (x: Int, y: Int)Int

scala> scala> scala> scala> val partialyProduit = produit(2,_:Int)produit(2,_:Int)produit(2,_:Int)produit(2,_:Int)partialyProduit: Int => Int = <function1<function1<function1<function1>>>>

scala> scala> scala> scala> partialyProduit(7)res10: Int = 14

[email protected]. MICHRAFY 25

Page 26: Scala : programmation fonctionnelle

Fonction récursive• Une fonction récursive est une fonction qui peut s’appeler

elle-même.

• La récursivité reproduit le formalisme de la relation de récurrence en mathématique

• La récursivité doit satisfaire deux conditions :• Un ou plusieurs cas d’arrêts qui ne font pas appel à la fonction• Définir le cas général en fonction des états antérieurs

• La récursivité est un principe fondamental en programmation fonctionnelle, permettant de remplacer les boucles.

[email protected]. MICHRAFY 26

Page 27: Scala : programmation fonctionnelle

Fonction récursive : intérêt• Pour des structures de données récursives, il est bien

plus facile d'écrire des algorithmes récursifs qu'itératifs

• Certains algorithmes sont extrêmement difficiles à écrire dans un style itératif

• Dans certains cas, les fonctions récursives permettent d’écrire des programmes très lisibles, et aussi de concevoir des algorithmes dont l'analyse ou la preuve sera facilitée.

[email protected]. MICHRAFY 27

Page 28: Scala : programmation fonctionnelle

Fonction récursive : Calcul PGCD

[email protected]. MICHRAFY 28

a = kb + r et 0 ≤ r < b

a si b=0PGCD(b,r) PGDC(a,b)=

Algorithme d’Euclide

appel à PGCD(42,24). Appel a PGCD(24,18).. Appel à PGCD(18,6)…Appel à PGCD(6,0)….retour 6

scalascalascalascala> > > > defdefdefdef pgcdpgcdpgcdpgcd((((a:Int,b:Inta:Int,b:Inta:Int,b:Inta:Int,b:Int) : ) : ) : ) : IntIntIntInt ={={={={| | | | if(bif(bif(bif(b==0) a==0) a==0) a==0) a| | | | else else else else pgcdpgcdpgcdpgcd((((b,b%ab,b%ab,b%ab,b%a))))| }| }| }| }

pgcd: (a: Int, b: Int)Intscalascalascalascala> pgcd(42,24)res0: Int = 6

Page 29: Scala : programmation fonctionnelle

Fonction récursive : pile d’exécution• Chaque appel d’une fonction récursive est associé à un

contexte d’exécution propre• Ce contexte d’exécution est composé de :

• l'adresse mémoire de l'instruction qui a appelé la fonction• les valeurs des paramètres et des variables définies par la fonction

• La récursivité implique une allocation dynamique de la mémoire.

• La pile d’exécution fonctionne selon le principe LIFO• La pile ayant une taille fixe, une mauvaise utilisation de la

récursivité peut entraîner son débordement.

[email protected]. MICHRAFY 29

Page 30: Scala : programmation fonctionnelle

Fonction récursive : pile d’exécution appel à fact(4). 4*fact(3) = ?. appel à fact(3). . 3*fact(2) = ?. . appel à fact(2). . . 2*fact(1) = ?. . . appel à fact(1). . . . 1*fact(0) = ?. . . . appel à fact(0). . . . retour de la valeur 1. . . . 1*1. . . retour de la valeur 1. . . 2*1. . retour de la valeur 2. . 3*2. retour de la valeur 6. 4*6retour de la valeur 24

scalascalascalascala> > > > def fact(n : Int) : Int| = if(n==0) 1 else n*fact(n-1)

fact: (n: Int)Intscalascalascalascala> > > > fact(4)res2: Int = 24

1 si n=0n*fact(n-1)fact(n)=

[email protected]. MICHRAFY 30

Page 31: Scala : programmation fonctionnelle

La récursivité : terminale ou non ?

Deux types

Terminale Non Terminale

[email protected]. MICHRAFY 31

• Une fonction f est récursive terminale, si tous les appels récursifs invoquent f au plus une fois et sont de la forme return f(…)

• Une fonction récursive terminale a un coût en mémoire constant (pas d’empilement des appels récursifs).

• Il est toujours possible de transformer une fonction récursive non terminale en une fonction terminale en introduisant des accumulateurs comme arguments d’entrée

Page 32: Scala : programmation fonctionnelle

Récursivité : Transformationdef factNonTerminalfactNonTerminalfactNonTerminalfactNonTerminal(n:Int):Int ={

if(n==0) 1 else n+factNonTerminalfactNonTerminalfactNonTerminalfactNonTerminal(n-1)

}

[email protected]. MICHRAFY 32

def factTerminalfactTerminalfactTerminalfactTerminal(n:Int, m:Int) : Int ={if(n==0) melse factTerminalfactTerminalfactTerminalfactTerminal(n-1,m*n)

}

Transformation Terminale

Fonction récursivenon terminale

Fonction récursiveterminale

accumulateur

Page 33: Scala : programmation fonctionnelle

Récursivité : fonctions enveloppe et auxiliaire• Une fonction enveloppe est une fonction qui encapsule

une fonction ou plusieurs (nommée fonction enveloppée ou auxiliaire).

• Les fonctions enveloppes peuvent être utilisées pour initialiser les arguments d’une fonction récursive terminale

• La réécriture d’une fonction en récursivité terminalenécessite l’introduction d’un argument ou plusieurs et dontl’initialisation dépend de l’implémentation. La solutionconsiste à implémenter une fonction récursive terminalecomme une fonction auxiliaire d’une fonction principale

[email protected]. MICHRAFY 33

Page 34: Scala : programmation fonctionnelle

Récursivité : réécriture d’une fonctiondef factNonTerminalfactNonTerminalfactNonTerminalfactNonTerminal(n:Int):Int ={

if(n==0) 1 else n+factNonTerminalfactNonTerminalfactNonTerminalfactNonTerminal(n-1)

}

[email protected]. MICHRAFY 34

def factTerminalfactTerminalfactTerminalfactTerminal(n:Int, m:Int) : Int ={if(n==0) melse factTerminalfactTerminalfactTerminalfactTerminal(n-1,m*n)

}

Transformation Terminale

def factfactfactfact(n : Int) : Int = {def factTerminalfactTerminalfactTerminalfactTerminal(n:Int, m:Int) : Int ={

if(n==0) melse factTerminalfactTerminalfactTerminalfactTerminal(n-1,m*n)

}factTerminalfactTerminalfactTerminalfactTerminal(n,1(n,1(n,1(n,1))))

}

Réécriture de la fonction

Définition de la fonction auxiliaire

1

2

Appel à la fonction auxiliaire avec deux arguments dont un est initialisé à 1

Page 35: Scala : programmation fonctionnelle

Récursivité : Primalité d’un nombre• Un nombre p est premier s’il admet que deux diviseurs 1

et n• Tout nombre pair est non premier à l’exception de 2• Pour améliorer les performance, il suffit de tester

seulement les nombre entre 2 et √�.• Comme un nombre premier est toujours impair – à

l’exception de 2- il suffit de tester les nombre impairs entre 3 et √�.Mais ceci est utile pour un algorithme itératif

[email protected]. MICHRAFY 35

Page 36: Scala : programmation fonctionnelle

Récursivité : Primalité d’un nombre

def isPrimAuxisPrimAuxisPrimAuxisPrimAux((((p:Intp:Intp:Intp:Int, d:Int) , d:Int) , d:Int) , d:Int) : Boolean={if(d*d <= p){

if(p%d==0) falseelse isPrimAux(p,d+1);

}else true

}

def isPrimisPrimisPrimisPrim((((p:Intp:Intp:Intp:Int) ) ) ) : Boolean ={def isPrimAux(p:Int, d:Int):Boolean ={

if(d*d <= p){if(p%d==0) falseelse isPrimAux(p,d+1);

}else true

}isPrimAux(p,2)

}

d=2

isPrim(p) =

si d*d <= psi d/p alors fauxsinon estPrim(p,d+1)

sinon vrai

Algorithme pour tester la primalité

1

2

[email protected]. MICHRAFY 36

Page 37: Scala : programmation fonctionnelle

Récursivité: fonction d’ordre sup.• n et m deux entiers, n < m• Calculer A et B :

- � � ∑ ����� - � ∑ � ����

[email protected]. MICHRAFY 37

Similarité : la somme

!: �� → ��! � � �

#: �� → ��# � � �

� � $ !%�&�

���, � $ # �

���

Réécriture de A et B

Ecrire une fonction sum qui prend en entrée une fonction f

Idée

'() !, �,) � 0'�� + )! � � '() !, � � 1,) '����

Relation de récurrence .

Page 38: Scala : programmation fonctionnelle

Récursivité: fonction d’ordre sup.• n et m deux entiers, n < m• Calculer A et B :

- � � ∑ ����� - � ∑ � ����

[email protected]. MICHRAFY 38

!: �� → ��! � � �

#: �� → ��# � � � � � $ !%�&

���, � $ # �

���

'() !, �,) � 0'�� + )! � � '() !, � � 1,) '����

def sumsumsumsum(ffff: Int => Int, a: Int, b: Int): Int ={if (a > b) 0 else f(a) + sum(f, a + 1, b)

}

val A = sum(x=>x)val B = sum(x=>x*x)

def sumCompactesumCompactesumCompactesumCompacte(f: Int => Int): (Int, Int) => Int = {def sum(a: Int, b: Int): Int =if (a > b) 0 else f(a) + sum (a + 1, b)sum

}

Calcul de A et B

Page 39: Scala : programmation fonctionnelle

Récursivité : stratégie d’implémentation

• Un algorithme récursif peut donner lieu à plusieurs implémentations.

• Ce cas se présente lorsque le problème est composé de plusieurs sous-problèmes de même nature. Ceci est similaire au principe de diviser pour régner ou aux algorithmes relevant de la programmation dynamique.

• L’implémentation dépend à la fois de la :• La Stratégie du parcours ou de construction• L’initialisation des paramètres

• Une mauvaise implémentation peut pénaliser le temps de calcul.

Analysons la suite de Fibonacci

[email protected]. MICHRAFY 39

Page 40: Scala : programmation fonctionnelle

Récursivité : Fibonacci, version naïve

Fibonacci(n)=

0 si n = 01 si n =1Fibonacci(n-1) + Fibonacci(n-2)

Suite de fibonacci

def fibonaccifibonaccifibonaccifibonacci(n:Int) : Int = {if(n < 2) nelse fibonaccifibonaccifibonaccifibonacci(n-1) + fibonaccifibonaccifibonaccifibonacci(n-2)

}

[email protected]. MICHRAFY 40

Page 41: Scala : programmation fonctionnelle

Récursivité : analyse de l’algorithme Fibonacci 7

6 5

4 35 4

4 3 3 2 3 2 2 1

1 03 2 2 1 2 1 2 1 1 0

1 01 01 01 02 1

1 0

1 0

• Chaque nœud désigne un terme de la suite de fibonacci• Les nœuds -portant les valeurs 2 à 7- sont des appels récursifs• Les nœuds verts désignent les termes 0 et 1 de la suite fibonacci• On constate le calcul redondant généré par l’algori thme « naïf »de fibonacci .

Arborescence de Fibonacci(7)

7

0

[email protected]. MICHRAFY 41

Page 42: Scala : programmation fonctionnelle

Récursivité : algorithme constructif de fibonacci• Le problème consiste à ne pas recalculer le même terme

de fibonnaci plusieurs fois.• Remarquons que le terme n de Fibonacci nécessite le

calcul des termes de n-1 à 0.• Par conséquent, pour éviter le calcul redondant, nous

pouvons calculer le terme n en commençant par calculer le terme 0,1, 2 …. via la relation de récurrence.

• Pour calculer le terme n sans redondance, il faut mémoriser les termes n-1 et n-2.

• Nous avons besoin aussi d’un test d’arrêt, ce qui est le terme n.

[email protected]. MICHRAFY 42

Page 43: Scala : programmation fonctionnelle

Récursivité : Fibonacci, algorithme constructif

p, a1,a0 trois entiers

Fibonacci(n,p,a1,a0) =

n si n<2Fibonacci(n,p+1,a1+a0,a1) si p<na1+ a0 sinon

a0 = 0, a1=1 ( a0 et a1 2 termes consécutifs de fibonacci)

p=2, ( p varie de 2 à n)

Relation de récursivité

Etape d’initialisation

• C’est un algorithme constructif.• A chaque étape, l’algorithme conserve les deux états m-1, m-2• Les deux états consécutifs sont stockés dans a0 et a1• Les termes 0 et 1 sont utilisés dans la phase d’initialisation• Le terme n de Fibonacci est la somme de a0 et a1

[email protected]. MICHRAFY 43

Page 44: Scala : programmation fonctionnelle

Récursivité : Fibonacci, algorithme constructif

p, a1,a0 trois entiers

Fibonacci(n,p,a1,a0) =n si n<2Fibonacci(n,p+1,a1+a0,a1) si p<na1+ a0 sinon

2

10

3

1

4

2

5

3

4

65

7

n=7, p=2, a0=0, a1=1

def fibonaccifibonaccifibonaccifibonacci(n:Int):Int={def fibfibfibfib(n:Int, p:Int, a0:Int, a1:Int) : Int ={

if(n<2) nelse{if(p<n) fibfibfibfib(n, p+1, a1+a0,a1)else a1+a0

}}fib(n,2,1,0)

}

Plus de calcul redondant

0

7

Chaque ligne désigne les termes

consécutifs

[email protected]. MICHRAFY 44

Page 45: Scala : programmation fonctionnelle

Curryfication : principe

• La curryfication désigne l'opération transforme unefonction à plusieurs arguments à une fonction à unargument qui retourne une fonction prenant le reste desarguments. Elle permet de convertir une fonction avecplusieurs paramètres en créant une chaîne de fonction,chacun attendant un seul argument.

• En mathématique, on peut définir une fonction à plusieursvariables alors que le Lambda-calcul se limite à desfonctions avec une seule variable. Une correspondance« curryfication » bijective a été définie entre les fonctionsLambda-calcul et les fonctions multivariées

[email protected]. MICHRAFY 45

Page 46: Scala : programmation fonctionnelle

Curryfication : Transformation• A chaque fonction multivariées, on associe une fonction avec

une seule variable. La curryfication s’appuie sur les définition des fonctions partielles

,����� → ���, - → � � -

!. ∶ �� → �� → ��� → !. - � � � -

Curryfication

! ∶ �������� → ���, -, / → � � - � /

!.: ��0�� → ����� → ��-, / → � � - � /

!.,1 ∶ �� → %�� → ��&/ → � � - � /

� → !.- → !.,1

Fonctions de curryfication

� → !.

2

1

[email protected]. MICHRAFY 46

Page 47: Scala : programmation fonctionnelle

Curryfication : méthode add

scala> def add1add1add1add1(x:Double, y:Double):Double = x + yadd1add1add1add1: (x: Double, y: Double)Double

scala> def add1Curry = (x : Double) => (y : Double) => x + yadd1Curry: Double => (Double => Double)

scala> def add2add2add2add2(x:Int,y:Int,z:Int) : Int = x+y+zadd2: (x: Int, y: Int, z: Int)Int

scala> def add2Curryadd2Curryadd2Curryadd2Curry(x:Int) : Int => (Int => Int) = y => (z => x + y + z)add2Curryadd2Curryadd2Curryadd2Curry: (x: Int)Int => (Int => Int)

Curryfication

Curryfication

[email protected]. MICHRAFY 47

Page 48: Scala : programmation fonctionnelle

Références bibliographiques• Beginning Scala, par David Pollak, 2015• Programming in Scala, par Martin Odersky and al., 2011• Programming Scala, par Dean Wampler, Alex Payne, 2014• Functional Thinking par Neal Ford, 2014• Functional Programming in Scala, par Paul Chiusano,

Rúnar Bjarnason, 2014

[email protected]. MICHRAFY

Page 49: Scala : programmation fonctionnelle

Dr Mustapha MichrafyDataScientist, ATOS

Contact : [email protected]

[email protected]. MICHRAFY 49