SCALA
PROGRAMMATION FONCTIONNELLE
CONCEPTS ET MISE EN ŒUVRE
Dr Mustapha Michrafy
M. MICHRAFY
Contact de l’auteur :
datasci...
Contexte
Cette étude a été présentée dans le cadre
du séminaire « Data Science principes, outils
et applications » au labo...
Plan
• Objectif
• Prérequis
• Tout est fonction
• Fonction pure
• Fonction anonyme
• Fonction d’ordre supérieur
• Clôture
...
Objectif
Cette étude vise à présenter la
programmation fonctionnelle sous Scala.
datascience.km@gmail.comM. MICHRAFY 4
Prérequis
• Connaissance du langage Scala
• Notion de récursivité
datascience.km@gmail.comM. MICHRAFY 5
Tout est fonction
• Dans le paradigme fonctionnel, tout est fonction.
• Un traitement complexe est composé de plusieurs
fo...
Fonction en scala
• En scala, une fonction est un objet qui peut être affecté à
une variable.
• La définition d’une foncti...
Appel à une fonction en scala
• L’appel d’une fonction se fait via son nom, suivi par les
arguments d’entrée entre parenth...
Fonction pure
• Une fonction pure est une fonction qui respecte les 2
critères suivants :
1. La fonction est déterministe,...
Fonctions mathématiques
Fonction Sin def sin(x:Double) : Double = Math.sin(x)
Fonction
identité
def identite(x:Double) : D...
Fonctions mathématiques
scalascalascalascala> defdefdefdef sin(x : Double) : Doublesin(x : Double) : Doublesin(x : Double)...
Fonction anonyme : principe
• Une fonction anonyme en scala permet de définir une
fonction sans déclarer le nom de la fonc...
Fonction anonyme : syntaxe
• La syntaxe d’une fonction anonyme commence par une
liste d’arguments séparés par des virgules...
Fonction anonyme : invocation
scala> val add = (x:Int, y:Int) => x+y
add: (Int, Int) => Int = <function2>
scala> add(7,8)
...
Fonction anonyme : construction
scala> val add1:(Int, Int) => Int = (x:Int, y:Int) => x+y
add1: (Int, Int) => Int = <funct...
Fonction comme variable
• En scala et dans le paradigme fonctionnel en général,
nous pouvons utiliser une fonction comme v...
Fonction comme argument : déclaration
• Il est aussi possible de définir une fonction qui prend en
entrée une fonction
• C...
Fonction comme argument : exemple
scala>scala>scala>scala> def operationoperationoperationoperation(op:(op:(op:(op:(Int,In...
Fonction comme valeur de retour
• Il est aussi possible d’avoir une fonction comme valeur de
retour d’une fonction
• Dans ...
Fonction comme valeur de retour
scala>scala>scala>scala> def fabriqueFctAffinefabriqueFctAffinefabriqueFctAffinefabriqueFc...
La fonction composée
• La fonction composée (notée o en mathématique) est la
fonction qui prend en entrée deux fonctions e...
La fonction composée
datascience.km@gmail.comM. MICHRAFY 22
F(x) = x*x
G(x) = x+1
FoG(x) = F(G(x))
= F(x + 1) = x*x+1
Form...
Clôture : principe
• Une clôture ou fermeture est une fonction dont la valeur
de retour dépend de la valeur d'une ou plusi...
Clôture : exemple
scala> val a = 2
a: Int = 2
scala> val b = 3
b: Int = 3
scala> def affine(x:Int,y:Int):Int = aaaa*x + bb...
Fonction partielle
• En figeant les valeurs d’un sous-ensemble des
paramètres d’une fonction connue, on obtient une
foncti...
Fonction récursive
• Une fonction récursive est une fonction qui peut s’appeler
elle-même.
• La récursivité reproduit le f...
Fonction récursive : intérêt
• Pour des structures de données récursives, il est bien
plus facile d'écrire des algorithmes...
Fonction récursive : Calcul PGCD
datascience.km@gmail.comM. MICHRAFY 28
a = kb + r et 0 ≤ r < b
a si b=0
PGCD(b,r)
PGDC(a,...
Fonction récursive : pile d’exécution
• Chaque appel d’une fonction récursive est associé à un
contexte d’exécution propre...
Fonction récursive : pile d’exécution
appel à fact(4)
. 4*fact(3) = ?
. appel à fact(3)
. . 3*fact(2) = ?
. . appel à fact...
La récursivité : terminale ou non ?
Deux types
Terminale Non Terminale
datascience.km@gmail.comM. MICHRAFY 31
• Une foncti...
Récursivité : Transformation
def factNonTerminalfactNonTerminalfactNonTerminalfactNonTerminal(n:Int):Int ={
if(n==0) 1
els...
Récursivité : fonctions enveloppe et
auxiliaire
• Une fonction enveloppe est une fonction qui encapsule
une fonction ou pl...
Récursivité : réécriture d’une fonction
def factNonTerminalfactNonTerminalfactNonTerminalfactNonTerminal(n:Int):Int ={
if(...
Récursivité : Primalité d’un nombre
• Un nombre p est premier s’il admet que deux diviseurs 1
et n
• Tout nombre pair est ...
Récursivité : Primalité d’un nombre
def isPrimAuxisPrimAuxisPrimAuxisPrimAux((((p:Intp:Intp:Intp:Int, d:Int), d:Int), d:In...
Récursivité: fonction d’ordre sup.
• n et m deux entiers, n < m
• Calculer A et B :
- ∑ - ∑
datascience.km@gmail.comM. MIC...
Récursivité: fonction d’ordre sup.
• n et m deux entiers, n < m
• Calculer A et B :
- ∑ - ∑
datascience.km@gmail.comM. MIC...
Récursivité : stratégie d’implémentation
• Un algorithme récursif peut donner lieu à plusieurs
implémentations.
• Ce cas s...
Récursivité : Fibonacci, version naïve
Fibonacci(n)=
0 si n = 0
1 si n =1
Fibonacci(n-1) + Fibonacci(n-2)
Suite de fibonac...
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 ...
Récursivité : algorithme constructif de
fibonacci
• Le problème consiste à ne pas recalculer le même terme
de fibonnaci pl...
Récursivité : Fibonacci, algorithme constructif
p, a1,a0 trois entiers
Fibonacci(n,p,a1,a0) =
n si n<2
Fibonacci(n,p+1,a1+...
Récursivité : Fibonacci, algorithme constructif
p, a1,a0 trois entiers
Fibonacci(n,p,a1,a0) =
n si n<2
Fibonacci(n,p+1,a1+...
Curryfication : principe
• La curryfication désigne l'opération transforme une
fonction à plusieurs arguments à une foncti...
Curryfication : Transformation
• A chaque fonction multivariées, on associe une fonction avec
une seule variable. La curry...
Curryfication : méthode add
scala> def add1add1add1add1(x:Double, y:Double):Double = x + y
add1add1add1add1: (x: Double, y...
Références bibliographiques
• Beginning Scala, par David Pollak, 2015
• Programming in Scala, par Martin Odersky and al., ...
Dr Mustapha Michrafy
DataScientist, ATOS
Contact : datascience.km@gmail.com
datascience.km@gmail.comM. MICHRAFY 49
Prochain SlideShare
Chargement dans…5
×

Scala : programmation fonctionnelle

584 vues

Publié le

Ce document vise à présenter la programmation fonctionnelle sous Scala.
Les points abordés sont le paradigme fonctionnel, fonction anonyme, fonction d’ordre supérieur, Clôture, fonction partielle, la récursivité, Curryfication. Chaque notion est accompagnée par des exemples.

Publié dans : Données & analyses
0 commentaire
3 j’aime
Statistiques
Remarques
  • Soyez le premier à commenter

Aucun téléchargement
Vues
Nombre de vues
584
Sur SlideShare
0
Issues des intégrations
0
Intégrations
11
Actions
Partages
0
Téléchargements
9
Commentaires
0
J’aime
3
Intégrations 0
Aucune incorporation

Aucune remarque pour cette diapositive

Scala : programmation fonctionnelle

  1. 1. SCALA PROGRAMMATION FONCTIONNELLE CONCEPTS ET MISE EN ŒUVRE Dr Mustapha Michrafy M. MICHRAFY Contact de l’auteur : datascience.km@gmail.com datascience.km@gmail.com1
  2. 2. Contexte Cette étude a été présentée dans le cadre du séminaire « Data Science principes, outils et applications » au laboratoire Cermsem. datascience.km@gmail.comM. MICHRAFY 2
  3. 3. Plan • Objectif • Prérequis • Tout est fonction • Fonction pure • Fonction anonyme • Fonction d’ordre supérieur • Clôture • Fonction partielle • Récursivité • Curryfication datascience.km@gmail.comM. MICHRAFY 3
  4. 4. Objectif Cette étude vise à présenter la programmation fonctionnelle sous Scala. datascience.km@gmail.comM. MICHRAFY 4
  5. 5. Prérequis • Connaissance du langage Scala • Notion de récursivité datascience.km@gmail.comM. MICHRAFY 5
  6. 6. Tout est fonction • Dans le paradigme fonctionnel, tout est fonction. • Un traitement complexe est composé de plusieurs fonctions datascience.km@gmail.comM. MICHRAFY 6
  7. 7. 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 fonction Arguments d’entrée Valeur de retour Corps de la fonction datascience.km@gmail.comM. MICHRAFY 7
  8. 8. 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 () datascience.km@gmail.comM. MICHRAFY 8
  9. 9. 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 arguments 2. 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 fonction pure datascience.km@gmail.comM. MICHRAFY 9
  10. 10. Fonctions mathématiques Fonction Sin def sin(x:Double) : Double = Math.sin(x) Fonction identité def identite(x:Double) : Double = x Fonction constante def constante(x:Double) : Double = 7 Fonction affine def 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 datascience.km@gmail.comM. MICHRAFY 10
  11. 11. Fonctions mathématiques scalascalascalascala> defdefdefdef sin(x : Double) : Doublesin(x : Double) : Doublesin(x : Double) : Doublesin(x : Double) : Double ==== Math.sinMath.sinMath.sinMath.sin(x)(x)(x)(x) sin: (x: Double)Double scalascalascalascala> sin(80) res0: Double = -0.9938886539233752 scalascalascalascala> def identite(x : Double) : Double = {return x;} identite: (x: Double)Double scalascalascalascala> identite(80) res1: Double = 80.0 scalascalascalascala> def constante(x : Double) : Double = 13 constante: (x: Double)Double scalascalascalascala> constante(80) res2: Double = 13.0 scalascalascalascala> def affine(x : Double) : Double = 3*x + 5 affine: (x : Double)Double scalascalascalascala> affine(80) res3: Double = 245.0 datascience.km@gmail.comM. MICHRAFY 11 Signature de la fonction
  12. 12. 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 datascience.km@gmail.comM. MICHRAFY 12
  13. 13. 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 datascience.km@gmail.comM. MICHRAFY 13
  14. 14. Fonction anonyme : invocation scala> val add = (x:Int, y:Int) => x+y add: (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>? datascience.km@gmail.comM. MICHRAFY 14
  15. 15. Fonction anonyme : construction scala> 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 = 11 scala> 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 » datascience.km@gmail.comM. MICHRAFY 15
  16. 16. 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 + 1 valImpair: Int => Int = <function1> scala> valImpair(10) res3: Int = 21 La variable valImpair a pour valeur la fonction <function1> datascience.km@gmail.comM. MICHRAFY 16
  17. 17. 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 datascience.km@gmail.comM. MICHRAFY 17
  18. 18. Fonction comme argument : exemple scala>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+y add: (x: Int, y: Int)Int scala>scala>scala>scala> def produitproduitproduitproduit(x:Int, y:Int):Int = x*y produit: (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 add comme paramètre Appel à la fonction operation avec produit comme paramètre datascience.km@gmail.comM. MICHRAFY 18
  19. 19. 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é. datascience.km@gmail.comM. MICHRAFY 19
  20. 20. Fonction comme valeur de retour scala>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 datascience.km@gmail.comM. 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
  21. 21. 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 datascience.km@gmail.comM. MICHRAFY 21
  22. 22. La fonction composée datascience.km@gmail.comM. 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*x F: (x: Int)Int scala>scala>scala>scala> def GGGG(x : Int) : Int = x + 1 G: (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
  23. 23. 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 datascience.km@gmail.comM. MICHRAFY 23
  24. 24. Clôture : exemple scala> val a = 2 a: Int = 2 scala> val b = 3 b: Int = 3 scala> def affine(x:Int,y:Int):Int = aaaa*x + bbbb affine: (x: Int, y: Int)Int scala> affine(1,1) res7: Int = 5 a, b sont déclarées en dehors de la portée de la fonction affine datascience.km@gmail.comM. MICHRAFY 24
  25. 25. 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*y produit: (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 datascience.km@gmail.comM. MICHRAFY 25
  26. 26. 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. datascience.km@gmail.comM. MICHRAFY 26
  27. 27. 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. datascience.km@gmail.comM. MICHRAFY 27
  28. 28. Fonction récursive : Calcul PGCD datascience.km@gmail.comM. MICHRAFY 28 a = kb + r et 0 ≤ r < b a si b=0 PGCD(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 |||| elseelseelseelse pgcdpgcdpgcdpgcd((((b,b%ab,b%ab,b%ab,b%a)))) | }| }| }| } pgcd: (a: Int, b: Int)Int scalascalascalascala> pgcd(42,24) res0: Int = 6
  29. 29. 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. datascience.km@gmail.comM. MICHRAFY 29
  30. 30. 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*6 retour de la valeur 24 scalascalascalascala>>>> def fact(n : Int) : Int | = if(n==0) 1 else n*fact(n-1) fact: (n: Int)Int scalascalascalascala>>>> fact(4) res2: Int = 24 1 si n=0 n*fact(n-1)fact(n)= datascience.km@gmail.comM. MICHRAFY 30
  31. 31. La récursivité : terminale ou non ? Deux types Terminale Non Terminale datascience.km@gmail.comM. 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
  32. 32. Récursivité : Transformation def factNonTerminalfactNonTerminalfactNonTerminalfactNonTerminal(n:Int):Int ={ if(n==0) 1 else n+factNonTerminalfactNonTerminalfactNonTerminalfactNonTerminal(n-1) } datascience.km@gmail.comM. MICHRAFY 32 def factTerminalfactTerminalfactTerminalfactTerminal(n:Int, m:Int) : Int ={ if(n==0) m else factTerminalfactTerminalfactTerminalfactTerminal(n-1,m*n) } Transformation Terminale Fonction récursive non terminale Fonction récursive terminale accumulateur
  33. 33. 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é terminale nécessite l’introduction d’un argument ou plusieurs et dont l’initialisation dépend de l’implémentation. La solution consiste à implémenter une fonction récursive terminale comme une fonction auxiliaire d’une fonction principale datascience.km@gmail.comM. MICHRAFY 33
  34. 34. Récursivité : réécriture d’une fonction def factNonTerminalfactNonTerminalfactNonTerminalfactNonTerminal(n:Int):Int ={ if(n==0) 1 else n+factNonTerminalfactNonTerminalfactNonTerminalfactNonTerminal(n-1) } datascience.km@gmail.comM. MICHRAFY 34 def factTerminalfactTerminalfactTerminalfactTerminal(n:Int, m:Int) : Int ={ if(n==0) m else factTerminalfactTerminalfactTerminalfactTerminal(n-1,m*n) } Transformation Terminale def factfactfactfact(n : Int) : Int = { def factTerminalfactTerminalfactTerminalfactTerminal(n:Int, m:Int) : Int ={ if(n==0) m else 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
  35. 35. 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 datascience.km@gmail.comM. MICHRAFY 35
  36. 36. 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) false else 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) false else isPrimAux(p,d+1); } else true } isPrimAux(p,2) } d=2 isPrim(p) = si d*d <= p si d/p alors faux sinon estPrim(p,d+1) sinon vrai Algorithme pour tester la primalité 1 2 datascience.km@gmail.comM. MICHRAFY 36
  37. 37. Récursivité: fonction d’ordre sup. • n et m deux entiers, n < m • Calculer A et B : - ∑ - ∑ datascience.km@gmail.comM. 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.
  38. 38. Récursivité: fonction d’ordre sup. • n et m deux entiers, n < m • Calculer A et B : - ∑ - ∑ datascience.km@gmail.comM. 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
  39. 39. 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 datascience.km@gmail.comM. MICHRAFY 39
  40. 40. Récursivité : Fibonacci, version naïve Fibonacci(n)= 0 si n = 0 1 si n =1 Fibonacci(n-1) + Fibonacci(n-2) Suite de fibonacci def fibonaccifibonaccifibonaccifibonacci(n:Int) : Int = { if(n < 2) n else fibonaccifibonaccifibonaccifibonacci(n-1) + fibonaccifibonaccifibonaccifibonacci(n-2) } datascience.km@gmail.comM. MICHRAFY 40
  41. 41. 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’algorithme « naïf »de fibonacci. Arborescence de Fibonacci(7) 7 0 datascience.km@gmail.comM. MICHRAFY 41
  42. 42. 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. datascience.km@gmail.comM. MICHRAFY 42
  43. 43. Récursivité : Fibonacci, algorithme constructif p, a1,a0 trois entiers Fibonacci(n,p,a1,a0) = n si n<2 Fibonacci(n,p+1,a1+a0,a1) si p<n a1+ 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 datascience.km@gmail.comM. MICHRAFY 43
  44. 44. Récursivité : Fibonacci, algorithme constructif p, a1,a0 trois entiers Fibonacci(n,p,a1,a0) = n si n<2 Fibonacci(n,p+1,a1+a0,a1) si p<n a1+ 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) n else{ 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 datascience.km@gmail.comM. MICHRAFY 44
  45. 45. Curryfication : principe • La curryfication désigne l'opération transforme une fonction à plusieurs arguments à une fonction à un argument qui retourne une fonction prenant le reste des arguments. Elle permet de convertir une fonction avec plusieurs paramètres en créant une chaîne de fonction, chacun attendant un seul argument. • En mathématique, on peut définir une fonction à plusieurs variables alors que le Lambda-calcul se limite à des fonctions avec une seule variable. Une correspondance « curryfication » bijective a été définie entre les fonctions Lambda-calcul et les fonctions multivariées datascience.km@gmail.comM. MICHRAFY 45
  46. 46. 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 datascience.km@gmail.comM. MICHRAFY 46
  47. 47. Curryfication : méthode add scala> def add1add1add1add1(x:Double, y:Double):Double = x + y add1add1add1add1: (x: Double, y: Double)Double scala> def add1Curry = (x : Double) => (y : Double) => x + y add1Curry: Double => (Double => Double) scala> def add2add2add2add2(x:Int,y:Int,z:Int) : Int = x+y+z add2: (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 datascience.km@gmail.comM. MICHRAFY 47
  48. 48. 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 datascience.km@gmail.comM. MICHRAFY
  49. 49. Dr Mustapha Michrafy DataScientist, ATOS Contact : datascience.km@gmail.com datascience.km@gmail.comM. MICHRAFY 49

×