(* ###################################################### *) (* # # *) (* # TD 1 : P.F. et Decouverte de CAML # *) (* # # *) (* ###################################################### *) 1) Intro a la programmation fonctionnelle. ########################################## Montrer difference avec approche imperative sur un exemple : Somme des n premiers entiers. 2) Intro a CAML ############### * Objets de base ---------------- - constantes entieres = suite de chiffres decimaux : 26, -172, etc. - constantes reelles : 12.38, 0.15, .15, 2.0, 2. etc. - constantes booleennes : true, false. - constantes chaines : "oui", "bonjour". - identificateurs : suite "presque" quelconque de caracteres : fact, pgcd, +, = - quelques identificateurs designent des fonctions predefinies : arithmetiques : *, *., +, +., etc. booleennes : or, not, &. comparaison : =, <, >, <>. * Expressions ------------- notation peu differente de la notation normale : 2+3, sqrt(3.71), 1+true, 2+"oui", 3 < 2, 3 = 3 etc. * Dialogue avec CAML -------------------- "#" : invite de CAML, ";;" = fin d'une phrase # 2+2 ;; Reponse de CAML : - : int = 4 "-" indique qu'on a calcule une valeur "int" indique que la valeur est de type entier "4" et vaut 4. Rmq : CAML deduit toujours le type du resultat * Definitions ------------- --> donner un nom a une valeur. - definition globale # let s = 1+2+3 ;; (soit s = ...) s : int = 6 (CAML repond qu'on a defini un nom s, de type entier qui vaut 6) # les s2 = s * s ;; (s est utilisable dans d'autres calculs) s2 : int = 36 Definition = association d'un nom a une valeur Rmq : il est impossible de changer la valeur liees a un nom, a moins de redefinir ce nom. # let s = 1 ;; redefinit le nom s (un nom est donc une variable au sens mathematique : pas de notion d'affectation) - definition locale une definition globale est permanente, i.e. dure pendant toute la session CAML. On peut aussi vouloir utiliser un nom uniquement pour realiser un calcul donne ==> definition locale, i.e. temporaire, qui disparait a la fin de l'evaluation de la phrase ou elle se trouve. # let s = 20 in s * 4 ;; "in" mot cle veut dire "dans" - : int = 80 # s ;; - : int = 1 (la definition globale reste valable) * Fonctions ----------- Programme = suite de definitions de fonctions, suivie d'un appel a la fonction qui declenche le calcul voulu. ++ Definition globale d'une fonction # let succ (x) = x + 1 ;; succ : int -> int = On a defini le nom succ, ce nom a pour valeur une fonction (""), et a pour type int -> int, qui est le type des fonctions des entiers "int" vers les entiers "-> int" # succ ;; -: int -> int = le nom succ possede une valeur : valeur fonctionnelle. ++ Application d'une fonction # succ (2) ;; - : int = 3 Rmq : on peut supprimer les parentheses autour des noms des arguments des fonctions lors des definitions et des appels. # let succ x = x + 1 ;; # succ 2 ;; idem. ++ Definition locale d'une fonction locale a une expression : # let pred x = x - 1 in (pred 3) * (pred 4) -: int = 6 locale a une fonction : # let puiss4 x = let carre y = y * y in carre (carre x) ;; puiss4 : int -> int = # puiss4 3 ;; -: int = 81 ++ Fonctions a plusieurs arguments # let moy a b = (a + b) / 2 ;; moy : int -> int -> int = # let perimetre_rectangle longueur largeur = 2*(longueur + largeur) ;; perimetre_rectangle : int -> int -> int = la fonction prend deux arguments entiers et rend un entier. En fait, perimetre_rectangle est une fonction a un argument entier (longueur), dont le resultat est une fonction a un argument entier (largeur) et de resultat un entier. Cf cours. Autre notation qui exprime mieux cela (style indirect) (ne pas insister la dessus, le presenter "pour info", on reviendra la dessus naturellement plus tard. En attendant, recommander le style "direct"). # let perimetre_rectangle = function longueur -> function largeur -> 2*(longueur + largeur) ;; ceci est valable pour n'importe quel nombre de parametre : # let succ = function x -> x + 1 ;; # moy 5 3 ;; - : int = 4 # moy 2 3 ;; - : int = 2 Attention, il s'agit de la division entiere ! # let moyenne = function a -> function b -> (a + b) / 2 ;; Attention, on n'a pas le droit d'ecrire # let moyenne = function a b -> (a + b) / 2 ;; !!! Troisieme notation : on peut preciser le type de la fonction, bien que CAML le deduise automatiquement : # let (succ : int -> int) = function x -> x + 1;; # let (perimetre_rectangle : int -> int -> int) = function longueur -> function largeur -> 2*(longueur + largeur) ;; (la non plus, ne pas insister : montrer l'interet mais redire que ces 3 notations sont equivalentes) Interet : Ceci permet de traduire directement en CAML des definitions mathematiques du genre : soit succ : Z --> Z x |--> x + 1 # let (succ : int -> int) = function x -> x + 1;; - Fonctions anonymes On peut construire des fonctions sans leur donner d'identificateur. # (function x -> 2 * x + 1) ;; - : int -> int = # (function x -> 2 * x + 1) 2 ;; - : int = 5 ++ Usage des parentheses # succ ( 2 * 3) ;; - : int = 7 # succ 2 * 3 ;; - : int = 9 (en fait c'est (succ 2) * 3) = (2+1)*3 = 3*3 # moy 2 3 ;; OK # (moy 2) 3 ;; ERREUR # moy (2 3) ;; ERREUR moy est applique a 1 seul argument, au lieu de 2. # succ -3 ;; ERREUR # succ (-3) ;; OK # succ succ 1 ;; ERREUR : on applique 2 arguments (suuc et 1) a succ > Top level input > succ succ 1 ;; ^^^^ > Expression of type int -> int > cannot be used with type int -> a' -> b' CAML indique que l'expression soulignee (succ) est une fonction a un argument (int -> int). Elle ne peut etre utilisee avec un type different. # succ (succ 1) ;; OK * Types quelconques ------------------- Commenter : # let f x = 1 ;; f : a' -> int # let f x = x ;; f : a' -> a' # let f x y = x = y ;; f : a' -> a' -> bool # let f x y = "bonjour" ;; f : a' -> b' -> string 3) Preparation des T.P. ####################### en preparation (sic)