Programmation Fonctionnelle

Polytech Paris Saclay
2024-2025

Adrien Durier

OCaml

III. Listes & Types Algébriques

Type Produit *

  • (1,2) est de type int * int
  • (1,"WTF") est de type int * string
let u = (1, 2)
let uu = (1,"AAAAAAAAAh")
let f (x, y, z) w = if x + y < 0 then w^"NON" else z
let fst x = let (w,z) = x in w
let snd x = let (w,z) = x in w

Pourquoi 'produit'?

Comme le produit de deux ensembles:

A \times B = \{(x,y) | x\in A\text{ and }y\in B\}

III. Listes & Types Algébriques

Les Types 'Somme'

OCaml

Les Types 'Somme'

type soit_int_soit_string = 
	CestUnEntier of int | CestUnString of string
let x = CestUnEntier 8
let y = CestUnString "HUIT"
let liste_de_8 = [x;y]

Si j'ai besoin de mettre des entiers et des chaînes de caractères dans la même liste

Exemple

C'est comme la somme ensembliste

 

(aussi appelée l'union disjointe)

A+B

Les Types 'Somme'

type soit_int_soit_string = 
	| CestUnEntier of int 
    | CestUnString of string
let x = CestUnEntier 8
let y = CestUnString "HUIT"
let liste_de_8 = [x;y]

let extract_int x = match x with
 | CestUnEntier n -> n
 | CestUnString s -> 0

extract_int est de type

soit_int_soit_string -> int

Les Types 'Somme'

type soit_int_soit_string = 
	| CestUnEntier of int 
    | CestUnString of string
let x = CestUnEntier 8
let y = CestUnString "HUIT"
let liste_de_8 = [x;y]

let extract_int x = match x with
 | CestUnEntier n -> n
(* | CestUnString s -> 0 *)

extract_int est de type

soit_int_soit_string -> int

Mais on a un warning:

/!\ Pattern-matching non-exhaustive!

?

Les Types 'Somme'

type jour = 
	Lundi | Mardi | Mercredi | Jeudi | Vendredi |
    Samedi | Dimanche

let cours_de_PF = [Mardi; Mercredi; Vendredi]

let num_jour x = match x with
	Lundi -> 1 | Mardi -> 2 | Mercredi -> 3 | 
    Jeudi -> 4 | Vendredi -> 5 | Samedi -> 6 | 
    Dimanche -> 7

num_jour est de type

jour -> int

On peut aussi ne rien mettre comme ensemble.

Les Types 'Somme'

type jour = 
	Lundi | Mardi | Mercredi | Jeudi | Vendredi |
    Samedi | Dimanche

type soit_int_soit_string = 
	| CestUnEntier of int 
    | CestUnString of string
  • Lundi, Mardi ou CestUnString sont des 'constructeurs'
  • Les constructeurs commencent toujours par une majuscule
  • Seuls les constructeurs ont le droit de commencer par des majuscules (pas de variable Mavariable)

Les Types 'Somme'

  • On appelle ça du Filtrage (en français)
    ou du Pattern-Matching (en VO)
type soit_int_soit_string = 
	| CestUnEntier of int 
    | CestUnString of string

let extract_int x = match x with
 | CestUnEntier n -> n
 | CestUnString s -> 0

Les Types 'Somme'

type 'a option = Some of 'a | None

let x = None
let y = Some 4

let i_want_some x = match x with
 | Some p -> p
 | None -> failwith "je veux pas de ça"

let truc_bizarre n = let x = Some n in 
 (match x with Some p -> p) * 
 (match x with Some p -> p)

Le type 'option': Un Type Hyper Important !!

TM

Qu'est-ce qui se passe?

Les Types 'Somme'

type 'a option = Some of 'a | None

let x = None
let y = Some 4

let i_want_some x = match x with
 | Some p -> p
 | None -> failwith "je veux pas de ça"

let truc_bizarre n = let x = Some n in 
 (match x with Some p -> p) * 
 (match x with Some p -> p)

Le type option est présent de base dans OCaml.

Il sert à représenter les valeurs indéfinies

(on l'utilisera!)

Les Types 'Somme'

let i_want_some_or_not x = match x with
 | Some p -> p
 | None -> 0

Quel est le type de 'i_want_some_or_not' ?

Les Types 'Somme'

let i_want_some_or_not x = match x with
 | Some p -> p
 | None -> 0

Quel est le type de 'i_want_some_or_not' ?

int option -> int

De la récursivité dans mon type Somme

type t = Truc | Machin of t

let x = Machin (Machin (Machin (Machin (Truc))))

type tt = TTruc | MMachin of int * tt


Qu'est-ce que c'est donc que tt ?

De la récursivité dans mon type Somme

type t = Truc | Machin of t

let x = Machin (Machin (Machin (Machin (Truc))))

type tt = TTruc | MMachin of int * tt

let z = MMachin (3, MMachin(5, MMachin (2, TTruc)))

Qu'est-ce que c'est donc que tt ?

III. Listes & Types Algébriques

Les LISTES !!!

OCaml

Les Listes

type 'a list =
 | Empty
 | Cons of 'a * 'a list
  • [] est simplement le constructeur de la liste vide
  • x::l est Cons(x,l)
let rec somme l = match l with
 | [] -> 0
 | x :: xs -> x + somme xs

Les Arbres

type 'a arbre =
 | Feuille
 | Noeud 'a * 'a arbre * 'a arbre 
  • On peut aussi faire des arbres!

Les Listes

let rec recherche x l = match l with 
 | [] -> false
 | y :: ys -> y = x || recherche x ys

let rec recupere x l = match l with 
 | (y,z) :: ys -> if x = y then z else (* ??? *)
 | [] -> (* ??? *)

Comment récupérer un élément dans un

dictionnaire??

(sachant qu'il peut en être absent?)

Les Listes

let rec recherche x l = match l with 
 | [] -> false
 | y :: ys -> y = x || recherche x ys

let rec recupere x l = match l with 
 | [] -> None
 | (y,z) :: _ when x = y -> Some z
 | (y,z) :: ys -> recupere l ys
 
  • _ : 'on se fiche de sa valeur'
  • when permet d'ajouter des conditionnelles dans un filtrage plus élégamment
    (en évitant les 'if...')

III. Listes & Types Algébriques

Programmation récursive avec les listes

OCaml

Concaténer des Listes

let x = [1;2;3]@[4;5;6]

let rec append l1 l2 = match l1 with
 | [] -> l2
 | x :: xs -> x :: (append xs l2)




  • La concaténation de listes List.append, fait partie de la librairie List d'OCaml
  • Par essence, la concaténation de listes est inefficace:
    Obligés de parcourir toute la 1ère liste!
  • @ : sucre syntaxique pour  List.append

Concaténer des Listes

let x = [1;2;3]@[4;5;6]

let rec append l1 l2 = match l1 with
 | [] -> l2
 | x :: xs -> x :: (append xs l2)
 
let rec rev_append l1 l2 = match l1 with
 | [] -> l2
 | x :: xs -> append xs (x::l2)
  • Récursion Terminale: L'appel récursif doit être la dernière instruction à être évaluée
  • rev_append inverse la 1ère liste, mais elle est récursive terminale

Inversion de Listes

let rec reverse l = match l with
 | [] -> []
 | x :: xs -> (reverse xs) @ [x]
(* TRES inefficace! *)

let rec rev_append l1 l2 = match l1 with
 | [] -> l2
 | x :: xs -> append xs (x::l2)

let better_reverse l = 
	let rec rev_aux l1 l2 = match l1 with
	 | [] -> l2
 	 | x :: xs -> rev_aux xs (x::l2)
    in
    rev_aux l []

La fonction 'Map'

let rec map f l = match l with
 | [] -> []
 | x::xs -> f x :: (map f xs)

La fonction List.map est de type

('a -> 'b) -> 'a list -> 'b list

Quel type?

Fonction Mystère

let mystere l = let rec aux l x =
	match l with
	 | [] -> []:: x
	 | _ :: s -> aux s ( l :: x )
	in aux l []

Quel est le résultat de mystere [true;false;true]?

Que fait la fonction mystère ?

let mystere l = let rec aux l x =
	match l with
	 | [] -> []:: x
	 | _ :: s -> aux s ( l :: x )
	in aux l []

Quel est le résultat de mystere [true;false;true]?

Fonction Mystère

let mystere l = let rec aux l x =
	match l with
	 | [] -> []:: x
	 | _ :: s -> aux s ( l :: x )
	in aux l []

Quel est le résultat de mystere [true;false;true]?

Que fait la fonction mystère ?

III. Listes & Types Algébriques

Tris de listes

OCaml

Tri Insertion

let rec inserer x l =
	match l with
	| [] -> [x]
	| y::ys when x <= y -> x::l
    | y::ys -> y::(inserer x s)

let rec tri l = ...


COMPLETEZ !

Tri Insertion

let rec inserer x l =
	match l with
	| [] -> [x]
	| y::ys when x <= y -> x::l
    | y::ys -> y::(inserer x s)

let rec tri l = match l with
	| [] -> []
    | x::xs -> inserer x (tri xs)

C'est joli, non?

Tri rapide

let rec partage p l = match l with
 | [] -> ([] , [])
 | x::xs -> let (g,d) = partage p xs in
			  if x <= p then (x::g, d) 
        				else (g, x::d)

let rec tri_rapide l = match l with
 | [] -> []
 | p::ps -> let g,d = partage p ps in
			 (tri_rapide g)@[p]@(tri_rapide d)

Tri Fusion

let rec split l = match l with
 | [] -> [],[]
 | [x] -> [x],[]
 | x::y::s -> let g,d = split s in x::g,y::d

let rec merge l l' = match l,l' with
 | [],_ -> ...

 | x::xs,y::ys -> ...
 

let rec tri_fusion l = match l with
 ...



Tri Fusion

let rec split l = match l with
 | [] -> [],[]
 | [x] -> [x],[]
 | x::y::s -> let g,d = split s in x::g,y::d

let rec merge l l' = match l,l' with
 | [],_ -> l'
 | _,[] -> l
 | x::xs,y::ys when x <= y -> x :: (merge xs l')
 | x::xs,y::ys -> y :: (merge l ys)

let rec tri_fusion l = match l with
 ...
 
 

Tri Fusion

let rec split l = match l with
 | [] -> [],[]
 | [x] -> [x],[]
 | x::y::s -> let g,d = split s in x::g,y::d

let rec merge l l' = match l,l' with
 | [],_ -> l'
 | _,[] -> l
 | x::xs,y::ys when x <= y -> x :: (merge xs l')
 | x::xs,y::ys -> y :: (merge l ys)

let rec tri_fusion l = match l with
 | [] -> []
 | [x] -> [x]
 | _ -> let g,d = split l in 
 		merge (tri_fusion g) (tri_fusion d)