Programmation fonctionnelle
Table of Contents
1. Introduction test
1.1. Effets de bords
Le soucis des fonctions du paradigme impératif, c'est qu'on peut avoir des changements des paramètre dans d'autres fonctions. C'est ce que les fonctions pures règlent : la fonction renvoie toujours le même résultat. Haskell est un langage fonctionnel pur, càd qu'il n'a que des fonctions pures. C'est un langage strict (bonne nouvelle !). Il faut un peu se battre avec le compilateur, mais il est un bon garde-fous : si le code compile, alors il y a de fortes chances que le code soit correct.
1.2. Les expressions
prenons la fonction polynôme \(f(x) = ax^{2}+bx+c\)
En python, on l'écrirait :
def poly(a, b, c, x):
x1 = a*x*x
x2 = b*x
return x1 + x2 + c
En haskell, c'est :
poly a b c x = a*x*x + b*x + c
Il n'y a aucune instruction, que des expressions.
Opérateur de typage : ::. Par exemple :
(3+6)::Float
Et interdiction de faire (3::Float) + (5::Int), c'est vraiment pas bien et le compilateur sera bougon.
1.3. Les fonctions
La fonction doubler
doubler :: Integer -> Integer -- Typage de doubler
doubler x = 2*x -- Définition de doubler
La fonction estMajuscule
estMajuscule :: Char -> Bool
estMajuscule c = 'A' <= c && c <= 'Z'
1.4. Sous expression, sous fonctions
1.4.1. Déclaration where
<expr>
where
<decl1>
<decl2>
...
1.4.2. Expression let in
let
<decl1>
<decl2>
in <expr>
1.4.3. Exemple : différence de gaussiennes
dog :: Float -> Float -> Float -> Float -> Float
dog x y si so = g so - g si
where
g s = norm/s*exp (coords/s)
norm = 1 / (2*pi)
pi = 3.14159
coords = x*x + y*y
1.5. Opérateurs binaires
test :: Integer -> Integer -> (Integer -> Integer -> Integer) -> Integer
test a b f = f a b
test 3 5 + -- 8
test 3 5 * -- 15
Pour définir des opérateurs infixes, on écrit :
(+*) :: Int -> Int -> Int
(+*) a b = 2* (a+b)
1 +* 2
doubleSomme :: Int -> Int -> Int
a `doubleSomme` b = 2* (a+b)
doubleSomme 2 3
2 `doubleSomme` 3
1.6. Équivalent des structures de contrôle
1.6.1. Conditionnelle
En python :
def va(x):
res = x
if x < 0:
res = -x
return res
En Haskell
va :: Int -> Int
va a -> if a < 0 then -a else a
1.6.2. Gardes
func a1 a2 ... an
| <cond1> = <expr1>
| <cond2> = <expr2>
| otherwise = <exprDefault>
1.7. Types composés
1.7.1. Tuples
Type (Int, Int) : (1, 1), (4, 2)
Cas particulier ! Type Unit
sertARien :: Int -> ()
sertARien a = ()
1.7.2. Listes
Type [Float], Type[(Int, Char)]...
Fonctions null (vacuité), head tail, mais peu utilisées
1.8. Filtrage de motif
Exemple :
incrementTuple :: (Bool, Int, Int) -> (Bool, Int, Int)
incrementTuple t = ... ? -- Comment faire des opérations en fonction du bool ?
-- On fait :
incrementTuple t = case t of
(True, n1, n2) -> (True, n1, n1+n2)
(False, n1, n2) -> (False, n2, n1)
2. Types
2.1. Type somme
Type offrant une alternative entre plusieus sous-types possibles. Proche d'une enum ou union, ou est un enum en Rust.
2.2. Type produit
Type correspondant au produit cartésien des types qui le composent. Est une struct en C (mais les champs sont nommés).
2.3. Types algébrique
Un type algébrique est à la fois un type somme et un type produit
data Document
= Ecrit -> Int
| Audio -> Float, Float
| Image -> Int, Int
Mais on ne peut pas le print :c Il faut utiliser les dérivations
data Document
= Ecrit -> Int
| Audio -> Float, Float
| Image -> Int, Int
deriving Show
2.4. Utilisation des types algébriques
Filtrage de motif.
2.5. Type algébrique récursif
Géré par Haskell
data ListeInt
= Noeud Int ListeInt
| ListeVide
2.6. Enregistrement
Syntaxe
data T
= CA
{
c1 :: t1,
c2 :: t2
}
...
-- Instanciation. Il faut spécifier la valeur de tous les champs
ced = CA
{
c1 = ...,
c2 = ...
}
Les getters sont des fonctions qui sont le nom des enregistements
c1 CA 2 3 1 ...
3. Fonction d'ordre supérieur
Voir lambda calcul
L'opérateur flèche -> est associative à droite.
Une fonction peut être paramètre d'une autre fonction :
map :: (a -> b) -> [a] -> [b]
map _ [] = []
map f (x:xs) = f x : map f xs
3.1. Fonction lambda
On a besoin de littéraux de type fonction, pour éviter de donner des noms de fonctions à chaque fois. Pour cela, Haskell nous fournit une syntaxe pour les fonctions anonymes
-- \ est prononcé lambda
\ p -> <expression> :: tp -> te
3.2. Fonction en résultat de fonctions
Application partielle de fonction renvoie une fonction