Skip to content
Snippets Groups Projects
tp5.ml 7.11 KiB
Newer Older
(**********************************************************************)
(* 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) []