(* Liaisons *) (* I.1 Liaisons globales et locales *) let a = 2 ;; let f (x : int) : int = a * x ;; let a = 3 in f 1 ;; (* dans le calcul de f a garde la valeur lors de sa définition à savoir 2 et donc ce calcul renvoie la valeur 2. Notez que Caml signale que a est inutilisé ici *) let a = 3 ;; (* Même chose ici, la valeur de a dans la définition de f n'est pas modifiée. Mais on a une nouvelle liaison de a vers la valeur 3 *) f 1 ;; (* Et donc f 1 renvoie 2 aussi *) let x = 3 and x = 4 ;; (* I.2 *) let a = 80 ;; let b = a + 20 ;; let a = b + 50 in a + a * 3 ;; (* Le a utilisé dans le in vaut 150, par les priorités le résultat final est donc 600. La valeur de a n'est pas modifiée par ce calcul *) let a = 3 in let b = a + 2 in a + b ;; (* Ni la valeur de a ni celle de b ne sont modifiées par ce calcul. a y prend la valeur 3 et b vaut 5 d'où le résultat 8 *) let a = 3 in let a = 5 and b = a + 2 in a + b ;; (* Dans la liaison locale de b, a vaut 3 (et pas 5) d'où b = 5. Dans le calcul final a vaut 5, d'où une valeur finale de 10 *) 3 + (let a = 2 in 3 * a) ;; (* Ceci illustre que let.. in...;; est une expression avec un résultat, à savoir ici 6, d'où un résultat égal à 9 *) (* I.3 *) (* On a intérêt à calculer une fois pour toutes cos(ln(3)) et sin(ln(2) *) let cl3 = cos (log 3.) and sl2 = sin (log 2.) in (cl3 +. sl2) /. ( cl3 ** 3. -. sl2 ** 2.) ;; (* I.4 Liaisons locales imbriquées *) (* On peut proposer le calcul suivant. Noter la façon de nommer les variables de manière à bien les identifier dans le calcul final *) let log12 = log 12. in let llog12 = log log12 in 12. ** (log12 ** llog12) ;; (* II Fonctions simples *) (* II.1 *) let f x = x + 2 ;; let f2 = function x -> x + 2 ;; (* Il y a plusieurs façons syntaxiques de définir la fonction f*) let f3 = fun x -> x + 2 ;; (* Celle là aussi est correcte *) let f x = let a = 2 in a + x ;; (* tordue mais correcte !*) f 5 ;; (f 5) ;; f2 5 ;; f3 5 ;; let x = 5 in f x ;; (* Une façon compliquée proposée en TD mais qui n'est pas conseillée ... *) (* Attention à l'associativité à gauche pour calculer f(3*7) *) f (3 * 7) ;; (* OK *) f 3 * 7 ;; (* KO Cela calcule f(3) * 7 = 5 * 7 = 35 !! *) (* II.2 tangente hyperbolique *) let tanh (x : float) : float = let expx = exp x in (expx -. 1. /. expx) /. (expx +. 1. /. expx) ;; tanh 0.1 ;; (* II.3 Egalité de deux rationnels *) (* On teste simplement l'égalité des produits en "croix" *) let test_egalite ((n1, d1) : int * int) ((n2, d2) : int * int) : bool = n1 * d2 = n2 * d1 ;; (* Bien comprendre qu'après le premier =, le second est une expression booléenne qui vaudra true ou false et qui sera donc la valeur rendue par la fonction *) (* Version sans déconstruire les couples *) let test_egalite2 q1 q2 = (fst q1) * (snd q2) = (fst q2) * (snd q1) ;; (* Version où on déconstruit les couples avant de s'en servir *) let test_egalite3 (q1 : int * int) (q2 : int * int) : bool = let n1 = fst q1 and d1 = snd q1 and n2 = fst q2 and d2 = snd q2 in n1 * d2 = n2 * d1 ;; test_egalite (1, 2) (3, 6) ;; test_egalite (1, 2) (3, 7) ;; test_egalite2 (1, 2) (3, 6) ;; test_egalite2 (1, 2) (3, 7) ;; test_egalite3 (1, 2) (3, 6) ;; test_egalite3 (1, 2) (3, 7) ;; (* II.4 Géométrie analytique *) let dist ((x1, y1) : float * float) ((x2, y2) : float * float) : float = sqrt ((x2 -. x1) ** 2. +. (y2 -. y1) ** 2.) ;; dist (2., 4.) (5., 9.3) ;; let milieu (p : float * float) (q : float * float) : float * float = let x1 = fst p and y1 = snd p and x2 = fst q and y2 = snd q in ( (x1 +. x2) /. 2., (y1 +. y2) /. 2.) ;; milieu (2., 4.) (5., 9.3) ;; (* III Filtrage *) (* Une possibilité, il y en a de nombreuses autres : *) let et (bool1 : bool) (bool2 : bool) : bool = match bool1, bool2 with | true, _ -> bool2 | _, _ -> false ;; (* Vérifions...*) et true true ;; et true false ;; et false true ;; et false false ;; (* On remarque que le deuxième booléen n'est jamais utilisé dans le match. On peut donc l'enlever... *) let et2 (bool1 : bool) (bool2 : bool) : bool = match bool1 with | true -> bool2 | _ -> false ;; (* Vérifions...*) et2 true true ;; et2 true false ;; et2 false true ;; et2 false false ;; let ou (bool1 : bool) (bool2 : bool) : bool = match bool1, bool2 with | true, _ -> true | _, bool2 -> bool2 ;; (* Vérifions...*) ou true true ;; ou true false ;; ou false true ;; ou false false ;; let implique (bool1 : bool) (bool2 : bool) : bool = match bool1, bool2 with | false, _ -> true | _, bool2 -> bool2 ;; (* Vérifions...*) implique true true ;; implique true false ;; implique false true ;; implique false false ;; (* On peut aussi utiliser la définition mathématique p => q <=> non p ou q *) let implique2 (bool1 : bool) (bool2 : bool) : bool = ou (not bool1) bool2 ;; (* Vérifions...*) implique2 true true ;; implique2 true false ;; implique2 false true ;; implique2 false false ;; (* IV Typage *) (* IV.1 Correction *) let f m = 1 + sqrt m ;; (* Laissé faux pour voir la réponse de Caml *) let f (m : float) : float = 1. +. sqrt m ;; (* Corrigé *) let g m = match m with | 0 -> m | _ -> sqrt m ;; (* Version fausse pour voir la réponse de Caml *) let g (m : float) : float = match m with | 0. -> m | _ -> sqrt m ;; (* Idem *) (* IV.2 Devinette *) let h (f, g) = function x -> f (g x) ;; (* h est une fonction qui prend un couple de fonctions f et g (car g s'applique à quelque chose, ici x, et f s'applique à quelque chose, ici (g x)), et qui rend une fonction (mot clé function), à savoir la fonction qui à x associe f(g(x)). Autrement dit elle rend la fonction résultant de la composition de f et g : f o g. Son type est donc ('a -> 'b) * ('c -> 'a) -> ('c -> 'b). Mais les dernières parenthèses sont inutiles et même enlevées par Caml à cause de l'associativité des type à droites, qui rend donc ('a -> 'b) * ('c -> 'a) -> 'c -> 'b *) (* La version curryfiée prend deux paramètres qui sont deux fonctions *) let h f g = function x -> f (g x) ;; (* Le type est alors ('a -> 'b) -> ('c -> 'a) -> 'c -> 'b : on remplace le couple (f, g) par type(f) -> type(g). Assurez-vous de bien comprendre la nécessité des parenthèses dans cette expression *) (* IV.3 Une plus costaude *) (* La lecture du code montre que nécessairement n est un entier et que f est un fonction qui doit pouvoir s'appliquer au résultat de l'appel de composition f (n-1) à x. Comme dans le cas n = 0 elle rend la fonction identité, le type de x n'est pas fixé, et la fonction f doit rendre un résultat du même type que son argument C'est donc que f est du type 'a -> 'a. Au total composition est du type ('a -> 'a) -> int -> 'a -> 'a *) let rec composition f n = match n with | 0 -> (function x -> x) | n -> (function x -> (f ((composition f (n - 1)) x))) ;; (* Et clairement cette fonction rend la fonction f composée n fois avec elle-même, avec pour cas de base que pour n = 0 c'est la fonction identité *)