Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
(**********************************************************************)
(* 1 Manipulations de listes à l'aide de fonctions génériques *)
(**********************************************************************)
(**********************************************************************)
(* 1.1. Utilisation des fonctions sur les listes *)
(** Une fonction `f1` qui prend une liste d'`int` et renvoie la liste de leur représentation sous forme de `string`. *)
let f1 (l : int list) : string list = List.map (fun x -> string_of_int x) l
(* ou bien *)
let f1 = List.map string_of_int;;
assert (f1 [ 1; 2 ] = [ "1"; "2" ])
(** Une fonction `f2` qui prend un `int` `x` et une liste d'`int` `l` et renvoie la liste transformée en multipliant chaque élément de `l` par `x`. *)
let f2 (x : int) (l : int list) : int list = List.map (fun y -> x * y) l
(* ou bien *)
let f2 (x : int) : int list -> int list = List.map (fun e -> x * e);;
assert (f2 3 [ 1; 5; 3 ] = [ 3; 15; 9 ])
(** Une fonction `f3` qui prend deux `int` `x` et `y` et une liste d'`int` `l` et renvoie la liste (de `bool`) indiquant pour chacun des éléments de `l` s'il est bien compris entre `x` et `y`. *)
let f3 (x : int) (y : int) (l : int list) : bool list =
List.map (fun e -> x <= e && e <= y) l
(* ou bien *)
let f3 (x : int) (y : int) : int list -> bool list =
List.map (fun e -> x <= e && e <= y)
;;
assert (f3 3 7 [ 1; 4; 2; 12 ] = [ false; true; false; false ])
(** Une fonction `f4` qui prend deux `int` `x` et `y` et une liste d'`int` `l` et renvoie la liste des éléments de `l` qui sont compris entre `x` et `y`. *)
let f4 (x : int) (y : int) (l : int list) : int list =
List.filter (fun e -> x <= e && e <= y) l
(* ou bien *)
let f4 (x : int) (y : int) : int list -> int list =
List.filter (fun e -> x <= e && e <= y)
;;
assert (f4 3 7 [ 1; 4; 2; 12 ] = [ 4 ])
(** Une fonction `f5` qui prend une liste de liste d'`int` et renvoie la liste sans les (sous-)listes vides. *)
let f5 (l : int list list) : int list list = List.filter (fun l' -> l' != []) l
(* variante avec (=) *)
let f5 : int list list -> int list list = List.filter (( != ) []);;
assert (f5 [ []; [ 2; 3 ]; []; [ 1 ] ] = [ [ 2; 3 ]; [ 1 ] ])
(** Coder une fonction `f6` qui prend une liste d'`int option` `l` et renvoie une liste d'`int` contenant les valeurs `int` contenues dans `l`. Par exemple, `f6 [ Some 3; None; Some 18; Some 42; None; Some 37; None]` vaudra `[3; 18; 42; 37]`. *)
let f6 (l : int option list) : int list =
let l1 = List.filter (fun o -> o != None) l in
List.map
(fun o ->
match o with
| None -> 0 (* n'arrive pas à cause du filter précédent *)
| Some x -> x)
l1
(* ou bien *)
let f6 (l : int option list) : int list =
l
|> List.filter (( != ) None)
|> List.map (fun o ->
match o with
| None -> 0 (* n'arrive pas à cause du filter précédent *)
| Some x -> x)
(* ou encore en utilisant Option.get *)
let f6 (l : int option list) : int list =
l |> List.filter (( != ) None) |> List.map Option.get
;;
assert (
f6 [ Some 3; None; Some 18; Some 42; None; Some 37; None ] = [ 3; 18; 42; 37 ])
(**********************************************************************)
(* 1.2. Recodage de fonctions sur les listes *)
let rec map (f : 'a -> 'b) (l : 'a list) : 'b list =
match l with [] -> [] | x :: l' -> f x :: map f l'
let rec filter (f : 'a -> bool) (l : 'a list) : 'a list =
match l with
| [] -> []
| x :: l' -> if f x then x :: filter f l' else filter f l'
let rec for_all (f : 'a -> bool) (l : 'a list) : bool =
match l with [] -> true | x :: l' -> f x && for_all f l'
(**********************************************************************)
(* 2 Arbre n-aires: recodage *)
(**********************************************************************)
(**********************************************************************)
(* 2.1. Recodage de quelques fonctions de base avec la bibliothèque
standard OCaml *)
type 'a arbre_n = Feuille of 'a | Noeud of 'a arbre_n list
(**
Calcule la hauteur d'un arbre.
@param a l'arbre dont on veut calculer la hauteur
@return la hauteur de l'arbre
*)
let rec hauteur_arbre (a : 'a arbre_n) : int =
match a with
| Feuille _ -> 1
| Noeud foret ->
let hauteurs = List.map hauteur_arbre foret in
let h_max = List.fold_left max 0 hauteurs in
h_max + 1
(**
Extrait les éléments d'un arbre dans une liste
@param l'arbre dont on veut les éléments
@return la liste des éléments de l'arbre obtenue par un parcours en profondeur.
*)
let list_of_arbre : 'a arbre_n -> 'a list =
(*
Ajoute les éléments de l'arbre à la liste.
@param a l'arbre dont on veut extraires les éléments
@param acc la liste à laquelle on veut ajouter les éléments.
*)
let rec list_of_arbre_aux (a : 'a arbre_n) (acc : 'a list) : 'a list =
match a with
| Feuille x -> x :: acc
| Noeud foret ->
List.fold_left (fun acc2 fils -> list_of_arbre_aux fils acc2) acc foret
in
fun a -> list_of_arbre_aux a []
(**********************************************************************)
(* 2.2. Gestion d'option, fold et minimum *)
(**
[lift_option_2 f] choisi son deuxième argument si son premier argument est None.
Sinon utilise f pour produire une valeur avec ses deux arguments.
@param f la fonction utilisée pour combiner les arguments
@param x une option
@param y la valeur à combiner à la valeur de x ou à prendre si x est None
@return Some de la combinaison des valeurs de x et y, ou bien y si x est None
*)
let lift_option_2 (f : 'a -> 'a -> 'a) : 'a option -> 'a -> 'a option =
fun x y -> match x with None -> Some y | Some x' -> Some (f x' y)
(**
aggrège une valeur en utilisant un accumulateur et une fonction appelée pour
mettre à jour l'accumulateur en fonction de l'élément de l'arbre rencontrée.
Appelle la fonction en utilisant les un après les autres tous les éléments de
l'accumulateur.
@param f la fonction de mise à jour de l'accumulateur
@param init la valeur de départ de l'accumulateur
@param a l'arbre à parcourir
@return la valeur de l'accumulateur résultant des mises à jour
successives par les appels à f sur les éléments de a.
*)
let rec fold_left_arbre (f : 'b -> 'a -> 'b) (init : 'b) (a : 'a arbre_n) : 'b =
match a with
| Feuille x -> f init x
| Noeud foret -> List.fold_left (fold_left_arbre f) init foret
(* Pour le dernier cas on aurait pu écrire
List.fold_left (fun acc fils -> fold_left_arbre f acc fils) init foret
mais c'est plus long
*)
(**
Aggrège une valeur en utilisant une fonction de combinaison de valeurs
@param f la fonction de combinaison de valeurs
@param a l'arbre dont on veut combiner les valeurs
@return Some du résultat de la combinaisons des valeurs de a par f,
ou None si a n'a pas d'élément
*)
let reduce (f : 'a -> 'a -> 'a) (a : 'a arbre_n) : 'a option =
fold_left_arbre (lift_option_2 f) None a
(**
Extrait les éléments d'un arbre dans une liste
@param l'arbre dont on veut les éléments
@return la liste des éléments de l'arbre obtenue par un parcours en profondeur.
*)
let list_of_arbre' : 'a arbre_n -> 'a list =
fold_left_arbre (fun l e -> e :: l) []