On pourra comparer cette version OCAML avec la version HASKELL voire la version Python .
OCaml
(* Le but est d'ajouter des constantes symboliques comme Pi. *) (* Il faut bien choisir comment étendre la structure de données de *) (* manière avoir un joli code derrière. *) (* Pour l'exercice on ajoute juste pi et e, mais il faut imaginer que *) (* dans le futur on en ajoutera d'autres. *) (* Solution pas viable : *) type expr0 = | Num of float | Var of string | Add of expr0 * expr0 | Symb of string (* Pas bon car pas d'aide de la part du système de types sur les *) (* erreurs potentielles avec les string. *) (* Assoc pour l'environnement *) type envir = (string*float) list let rec assoc s (env : envir) = match env with | [] -> failwith "Variable inconnue" | (x,f)::r -> if x = s then f else assoc s r (* 1ere solution *) type expr1 = | Num of float | Var of string | Add of expr1 * expr1 | Pi | E (* Pas de difficulté pour coder eval. *) let rec eval env e = match e with | Num f -> f | Var s -> assoc s env | Add (e1,e2) -> (eval env e1) +. (eval env e2) | Pi -> 3.14 | E -> 2.7 (* Attention! Comment associer *) (* une valeur numérique aux valeurs symboliques. *) (* Problème de cette solution : ici on ne le voit pas très clairement, *) (* mais il faut se projeter sur les autres fonctions, en *) (* particulier la dérivation. Toutes les constantes symboliques se *) (* dérivent de la même manière. Et pour éval aussi, toutes les *) (* constantes se manipulent de la même manière : on renvoit un *) (* nombre. Donc il faudrait factoriser ce traitement, et pour cela *) (* avoir un constructeur dédié dans la structure de données -> *) (* solution 2. *) (* Solution 2. *) type symbol = Pi | E ;; type expr = | Num of float | Var of string | Add of expr * expr | Mul of expr * expr | Cos of expr | Sin of expr | SConst of symbol let value_of s = match s with | Pi -> 3.14 | E -> 2.7 let rec eval2 env e = match e with | Num f -> f | Var s -> assoc s env | Add (e1,e2) -> (eval2 env e1) +. (eval2 env e2) | SConst v -> value_of v (* Problème : value_of est un peu rigide. Solution : mettre cette *) (* fonction en paramètre. *) (* Solution 2 bis (même structure de données que la solution 2) : *) let rec eval env values e = match e with | Num f -> f | Var s -> assoc s env | Add (e1,e2) -> (eval env values e1) +. (eval env values e2) | Mul (e1,e2) -> (eval env values e1) *. (eval env values e2) | Cos e -> cos (eval env values e) | Sin e -> sin (eval env values e) | SConst v -> values v (* Exemple d'utilisation : *) let val_1 s = match s with | Pi -> 3.1 | E -> 2.7 let val_2 s = match s with | Pi -> 3.14 | E -> 2.71 let exemple = Mul(Cos (SConst Pi), Add (Var "x", Add(Var "y", Num 1.))) let env1 = [ ("x",2.) ; ("y",10.) ] let ex_eval = eval env1 val_2 exemple let rec deriv var = function | Num f -> Num 0. | Var s -> if s = var then Num 1. else Num 0. | Add (e1, e2) -> Add (deriv var e1, deriv var e2) | Mul (e1, e2) -> Add (Mul (e1, deriv var e2), Mul (e2, deriv var e1)) | Cos e -> Mul (Mul (Num (-1.), deriv var e ), Sin e) | Sin e -> Mul (deriv var e, Cos e) | SConst v -> Num 0. let ex_eval_der = eval env1 val_2 (deriv "x" exemple) (* ou si on a un moyen d'avoir les constantes avec une précison *) (* arbitraire : *) (* let val_n n s = match s with *) (* | Pi -> calcule_pi n *) (* | E -> calcule_e n *) (* let val_10 = val_n 10 ;; *)
Un exemple à améliorer de carnet d'adresse
OCaml
type tel = string ;; type personne = { nom : string ; anniv : (int * int) option ; tel : tel list ; adr : string list ; email : (string * string) list } type carnet = personne list let get_adresse s = match s.adr with | [] -> None | a :: _ -> Some a let find_adresse n (c:carnet) = get_adresse (List.find (fun p -> p.nom=n) c)