0% ont trouvé ce document utile (0 vote)
15 vues25 pages

PF Cours 2

Ce document traite des fonctions anonymes et des fonctions pures en programmation fonctionnelle, en expliquant leurs caractéristiques et leur utilité. Il aborde également le concept de fermetures, de fonctions de première classe et de fonctions d'ordre supérieur, soulignant l'importance de l'abstraction et de la composition fonctionnelle. Enfin, il illustre comment les fonctions peuvent être utilisées comme des valeurs, permettant des opérations telles que l'affectation à des variables et le passage en tant qu'arguments.
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
15 vues25 pages

PF Cours 2

Ce document traite des fonctions anonymes et des fonctions pures en programmation fonctionnelle, en expliquant leurs caractéristiques et leur utilité. Il aborde également le concept de fermetures, de fonctions de première classe et de fonctions d'ordre supérieur, soulignant l'importance de l'abstraction et de la composition fonctionnelle. Enfin, il illustre comment les fonctions peuvent être utilisées comme des valeurs, permettant des opérations telles que l'affectation à des variables et le passage en tant qu'arguments.
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

Programmation fonctionnelle

Cours 2
Fonctions

1
Fonction anonyme

• Une fonction standard a un nom, une liste de paramètres, un type de


retour et un corps.
• Si vous ne donnez pas de nom à une fonction, c'est une fonction
anonyme.
def doubler(i: Int) = { i * 2 }
(i: Int) => { i * 2 }

• La première ligne définit une fonction standard.


• La deuxième ligne définit la même fonction sans nom. La deuxième ligne
définit donc une fonction anonyme.
• Une fonction normale utilise le symbole = tandis qu'une fonction
anonyme utilise le symbole =>. Certaines personnes l'appellent une
fonction anonyme tandis que d'autres peuvent la désigner comme lambda.
2
Fonction anonyme

• Cependant, fonction anonyme et lambda sont deux noms différents pour


la même chose. Vous vous demandez peut-être comment appeler cette
fonction si elle n'a pas de nom. Vous pouvez l'affecter à une variable.
def doubler(i: Int) = { i * 2 }
(i: Int) => { i * 2 }
val d = (i: Int) => { i * 2 }

• Maintenant, vous pouvez l'appeler en utilisant la variable.

3
À quoi sert une fonction anonyme?

• Il peut y avoir des scénarios dans lesquels vous souhaitez créer une
fonction en ligne pour une utilisation unique.
• Donner un nom à une fonction n'a aucun sens si vous ne voulez pas
l'utiliser ailleurs. Dans ces scénarios, la création d'une fonction anonyme
est assez pratique.
def getOps(c: Int) = { Nous pouvons
def doubler(x: Int) = x * 2 faire la même
def tripler(x: Int) = x * 3 chose en utilisant
des fonctions def getOps2(c: Int) = {
if (c > 0)
anonymes. if (c > 0) (i: Int) => i * 2
doubler _
else (i: Int) => i * 3
else
}
tripler _
}

4
Transformation

• Nous pouvons appliquer un autre raccourci et déplacer la liste des


paramètres d'entrée en dehors du corps.

def getOps2(c: Int) = {


if (c > 0) (i: Int) => i * 2
else (i: Int) => i * 3
}

def getOps2(c: Int) = (i: Int) => {


if (c > 0) i * 2
else i * 3
}

5
Fonctions pures

• Les fonctions pures encouragent des méthodes de programmation sûres.


• Une fonction avec effet secondaire vous oblige à consulter la
documentation ou le code source.
• De l'autre côté, les fonctions Pure sont petites, précises, simples, sûres et
faciles à réutiliser.
• Une fonction pure garantit qu'ils ne modifieront rien en dehors de leur
corps.
• Vous pouvez les utiliser en toute confiance car vous savez qu'ils prennent
des entrées et donnent des résultats. Ils ne vous surprennent pas.

6
Fonctions pures

• Les fonctions pures sont plus composables ou modulaires.


• Il est courant dans PF de combiner de nombreuses fonctions dans une
solution simple.
• Vous verrez souvent du code de programmation fonctionnelle écrit
comme une chaîne d'appels de fonction.
• Le pseudo-code ci-dessous représente une chaîne d'appels de fonction.

val x = mesdonné[Link](a).
.alorsCe(b)
.etEnsuiteCe(c)
.etAussiCa(d)
.etEnfinCeci(e)

7
Fonctions pures
val x = mesdonné[Link](a).
.alorsCe(b)
.etEnsuiteCe(c)
.etAussiCa(d)
.etEnfinCeci(e)
• Le code ci-dessus prend un ensemble de données et applique une
chaîne de fonctions.
• Vous pouvez également faire des choses similaires avec des fonctions
non pures, mais c'est facile pour les fonctions pures car elles n'ont pas
d'effet secondaire et la sortie dépend uniquement des valeurs d'entrée.
• Nous appelons cette capacité la composition fonctionnelle.
• Vous pouvez combiner plusieurs fonctions avec plus de confiance si
vous savez qu'il n'y a pas d'effets secondaires.

8
Fonctions pures
• Comme il n'y a pas d'effets secondaires et que la sortie dépend
uniquement de l'entrée, vos cas de test sont simples.
• Il vous suffit de transmettre la valeur connue et d'affirmer la valeur
attendue. Alors que la simulation des effets secondaires est un
véritable défi pour les tests.
• Par exemple, supposons que vous ayez deux fonctions.
• Unpure Hello World
• Pure Hello World
• La première fonction n'est pas pure, elle imprime donc Hello World
sur la console.
• La deuxième fonction est pure, elle renvoie donc Hello World et n'écrit
rien sur la console. Vous pouvez rapidement automatiser le scénario de
test pour affirmer la valeur de retour.
9
Fonctions pures
• Les fonctions pures sont mémorisables.
• La mémorisation n'est rien d'autre que la mise en cache de fonctions
déterministes.
• Si vous savez que votre fonction est pure et que vous pouvez à
nouveau avoir besoin des résultats, vous pouvez mettre en cache la
sortie.
• Votre compilateur peut également effectuer la mise en cache en tant
qu'optimisation.
• Cependant, si vous avez des effets secondaires, vous ne pouvez pas
mettre en cache les résultats pour une utilisation ultérieure.

10
Fonctions pures
• Les fonctions pures peuvent être paresseuses (lazy).
• L'évaluation paresseuse est une idée convaincante dans le monde de la
programmation fonctionnelle.
• La paresse est principalement utilisée pour créer des structures de
données pour gérer efficacement de gros volumes de données.
• L'idée principale derrière l'opération paresseuse est d'attendre
l'évaluation d'une expression jusqu'à un stade ultérieur.
• Ce comportement est incroyablement puissant car il permet au
système de combiner les activités individuelles et de choisir une
méthode optimale pour atteindre le résultat global.

11
Qu'est-ce qu'une fermeture (closure)?
• Une fermeture est une fonction. Comme toute autre fonction Scala,
une fermeture peut être pure ou impure.
• Il peut être nommé ou anonyme, mais c'est avant tout une fonction.
• Vous vous demandez peut-être pourquoi nous appelons cela une
fermeture.
• Il y a une petite différence entre la fermeture et une fonction.

def getHike(salary:Double) = salary * p/100

• Le code ci-dessus est une définition de fonction. Il prend votre salaire


comme entrée. Ensuite, il calcule et renvoie votre valeur.

12
Free Variable
def getHike(salary:Double) = salary * p/100

• C'est le pourcentage de la randonnée. Où est la définition de p?


• La valeur p n'a aucune définition ou signification dans la fonction.
Alors, quel est le p?
• Le p est une variable libre pour cette fonction.
• Une fonction qui utilise une ou plusieurs variables libres est appelée
fermeture.
• C'est la seule différence entre une fonction et une fermeture. Une
fermeture utilise une ou plusieurs variables libres.

13
Free Variable

• Le compilateur Scala regarde dans l'environnement lexical local le


plus proche, dans lequel cette fonction a été définie et essaie de
trouver une liaison.
• Le compilateur détecte que la fonction n'a pas de définition locale pour
p et qu'elle ne fait même pas partie de la liste de paramètres. Ainsi, la
variable p est une variable libre et la fonction est une fermeture.
• Ensuite, il commence à chercher le p. Il commence à rechercher p
dans l'environnement lexical.

14
Free Variable
def getHike = {
//Charger l'employé et son salaire actuel
val e: Map[Int, Double] = Map(
1001 -> 35000.00,
1002 -> 43000.00,
1003 -> 28000.00,
1004 -> 54000.00,
1005 -> 17000.00
)
// Une certaine logique pour calculer le pourcentage pour chaque employé
val p: Map[Int, Double] =
Map(1001 -> 10.00, 1002 -> 12.00, 1003 -> 7.50, 1004 -> 6.80, 1005 -> 20.00)
(empID: Int) => (empID, e(empID) * p(empID) / 100.00)
}
val f = getHike
f(1001)
//f(1006) - [Link]: key not found: 100

15
Fonctions de première classe

• Un langage de programmation fonctionnel traite une fonction


comme toute autre valeur. Donc, si vous pouvez traiter une
fonction comme une valeur, cela signifie que vous devriez
pouvoir tout faire avec la fonction que vous pouvez faire avec
une valeur.
• Il y a trois opérations majeures que nous pouvons faire avec
des valeurs.
• Vous pouvez les affecter à une variable.
• Vous pouvez les transmettre comme argument à une fonction.
• Vous pouvez les renvoyer à partir d'autres fonctions.
Fonctions de première classe

• Traiter la fonction comme une valeur implique que vous devriez


également pouvoir effectuer les opérations ci-dessus avec une
fonction.
• Ainsi, vous pouvez faire les choses suivantes avec une fonction de
première classe.
• Vous pouvez affecter une fonction à une variable.
• Vous pouvez passer une fonction comme argument à une autre
fonction.
• Vous pouvez renvoyer une fonction à partir d'autres fonctions.
Attribuer une fonction à une variable

def doubler(i: Int) = i * 2


var d = doubler _
d(7)
//Output:- res0: Int = 14

 La première ligne du code ci-dessus définit une fonction Scala.


Le code est simple. Il prend un entier et renvoie la valeur
double. La ligne suivante affecte la fonction de doublage à une
variable d. Enfin, nous pouvons appeler la fonction en utilisant
la variable.
Passer une fonction comme argument à
une autre fonction Scala
val r = 1 to 10
//Output:- r: [Link] =
//Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
[Link](doubler)
//Output:- res4: [Link][Int] =
//Vector(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)

• La première ligne du code ci-dessus déclare une collection de


plages Scala. La deuxième ligne effectue un appel de méthode
de carte sur l'objet range et transmet également la fonction de
doublage en tant que paramètre.
Passer une fonction comme argument à
une autre fonction Scala
Fonction d'ordre supérieur

• La fonction d'ordre supérieur est un autre concept étroitement associé


aux fonctions de première classe. Vous pouvez définir une fonction
d'ordre supérieur comme indiqué ci-dessous.
• Une fonction qui effectue au moins l'une des opérations suivantes
est une fonction d'ordre supérieur.
• Prend une ou plusieurs fonctions comme arguments
• Renvoie une fonction comme résultat

21
Fonction Scala qui prend une autre
fonction comme argument
def doubler(i: Int) = i * 2
def tripler(i: Int) = i * 3
def applyF(f: Int => Int, x: Int) = f(x)
applyF(doubler, 5)
//Output:- res0: Int = 10
applyF(tripler, 5)
//Output:- res1: Int = 15
• La première et la deuxième ligne du code ci-dessus définissent deux
fonctions Scala.
• La troisième ligne définit une fonction d'ordre supérieur.
• La fonction applyF prend deux arguments. Le premier type d'argument
est une fonction et le deuxième argument est un entier. La ligne
suivante passe la fonction de doubleur à applyF. De même, la dernière
ligne passe également une fonction de tripleur à applyF. 22
Pourquoi des fonctions d'ordre supérieur?
• Nous pouvons passer des fonctions et les renvoyer.
• L'abstraction est le principal avantage des fonctions d'ordre supérieur.
L'abstraction rend l'application facilement extensible. Lorsque vous
développez avec un niveau d'abstraction plus élevé, vous
communiquez le comportement et moins l'implémentation.
var customers = Array("Ion", "Ana","Teodora","Ileana")
for (i <- 0 to [Link] - 1) {
println("Hi " + customers(i));
}

def remindPayment(x: String) = println("Payment reminder for " + x)


var i = 0;
for (i <- 0 to [Link] - 1) {
remindPayment(customers(i));
}
23
Pourquoi des fonctions d'ordre supérieur?
• La fonction forEach prend deux paramètres. Le premier paramètre est
un tableau de chaînes. Le deuxième paramètre est une fonction. Nous
parcourons le tableau et appelons la fonction. En fait, Scala fournit ce
type de méthode d'itération pour chaque collection. Vous n'avez donc
pas besoin d'implémenter une fonction forEach.

def remindPayment(x: String) = println("Payment reminder for " + x)


var i = 0;
for (i <- 0 to [Link] - 1) {
remindPayment(customers(i));
}

def forEach(a: Array[String], f: String => Unit) = {


for (i <- 0 to [Link] - 1)
f(a(i));
}
forEach(customers, remindPayment) 24
Merci de votre attention!

PF 2020-2021 25

Vous aimerez peut-être aussi