1 + 2 * 3 = 7Le moins unaire est noté ``
-'': ainsi - x désigne
l'opposé de x.
- (2 + 3) = -5 - 2 + 3 = 1
Mêmes conventions sur les précédences des opérateurs qu'en
mathématiques. Les constantes flottantes doivent impérativement
contenir un point .. Les opérateurs sont tous suffixés
par un point .:
-. (2.0 +. 3.0) = -5.0 -. 2.0 +. 3.0 = 1.0Le moins unaire est noté
-.: -. x désigne
l'opposé de x.
#"Par " ^ "exemple";; - : string = "Par exemple"
Les caractères spéciaux doivent être préfixés par le caractère
d'échappement \. Par exemple \n désigne un
retour chariot et \" une apostrophe.
Les chaînes très longues peuvent être écrites sur plusieurs lignes
terminées par un caractère d'échappement: les blancs écrits au début
de la ligne suivante seront ignorés
#"Par exemple: \ Ceci est une très \ longue chaîne";; - : string = "Par exemple: Ceci est une très longue chaîne"
#"Bonjour".[0];; - : char = `B` #let s = "Bonjour" in s.[0] <- `b`; s;; - : string = "bonjour"
L'entier désigné par un caractère représentant un chiffre:
#let digit_of_char c = (int_of_char c - int_of_char `0`);; digit_of_char : char -> int = <fun> #digit_of_char `7`;; - : int = 7La minuscule correspondant à une lettre:
#let lower_case c = char_of_int (int_of_char c + 32);; lower_case : char -> char = <fun> #lower_case `A`;; - : char = `a`Conversion inverse:
#let upper_case c = char_of_int (int_of_char c - 32);; upper_case : char -> char = <fun> #upper_case `a`;; - : char = `A`Les caractères non imprimables sont dénotés par leur code Ascii (sur 3 digits) en décimal.
#`\007`;; - : char = `\007` #`\048`;; - : char = `0`
Mêmes conventions sur les précédences des
opérateurs qu'en mathématiques: le ``et'' && a
priorité sur le ``ou'' || (pour les booléens
&& est similaire à la multiplication et
|| joue le rôle de l'addition). Ainsi
x || y && z est similaire à x + y * z et
donc implicitement parenthésé comme x || (y && z).
Passer une ligne:
#print_newline();; - : unit = ()Sans l'argument
(), l'évaluation de
print_newline réussit, mais n'appelle pas la procédure:
aucune ligne n'est imprimée.
#print_newline;; - : unit -> unit = <fun>(On obtient en résultat la procédure elle-même.)
Un nom définit par un ``let'' prend définitivement sa valeur au moment de la définition (on ne peut pas changer cette valeur).
let pi = 4.0 *. atan 1.0;;Une définition locale ne sert que pendant le temps d'un calcul: celui qui suit le mot-clef
in.
#let x = 1 in x + 1;; - : int = 2 #x;; Entrée interactive: >x;; >^ L'identificateur x n'est pas défini.On définit plusieurs noms en faisant suivre plusieurs définitions, séparées par le mot clef
and:
#let max = 100 and min = 10;; max : int = 100 min : int = 10
Définition de la fonction aire qui calcule l'aire d'un
carré de coté c
#let aire (c) = c * c;; aire : int -> int = <fun>Les parenthèses autour de l'argument sont facultatives:
#let cube x = x * x * x;; cube : int -> int = <fun>De même à l'appel:
#aire (4);; - : int = 16 #aire 16;; - : int = 256
Définition récursive simple let rec f x = ...:
#let rec fact x = if x = 0 then 1 else x * fact (x - 1);; fact : int -> int = <fun>
Pour les fonction définies par filtrage: l'argument est implicite, c'est celui qui sera confronté au filtrage:
#let rec fact = function | 0 -> 1 | x -> x * fact (x - 1);; fact : int -> int = <fun> #fact 10;; - : int = 3628800
let rec f x y = ...:
#let périmètre long larg = 2 * (long + larg);; périmètre : int -> int -> int = <fun>Fonctions sans arguments: on donne
() comme argument. Par
exemple une procédure pll qui imprime deux
retour-chariots successifs s'écrit:
#let pll () = print_newline(); print_newline();; pll : unit -> unit = <fun>et s'appelle, comme toutes les procédures, en lui appliquant
().
#pll ();; - : unit = ()
Les règles utilisées en Caml pour les opérateurs et fonctions sont analogues aux conventions des mathématiques pour les fonctions trigonométriques.
Argument simples (variables et nombres positifs): parenthèses facultatives.
Analogie trigonométrique: sin x, sin pi
Argument complexe: les parenthèses sont obligatoires.
Analogie trigonométrique: sin (x + y)
#let double x = x * 2;; double : int -> int = <fun> #double (1 + 2);; - : int = 6 #double (-1);; - : int = -2
Sans parenthèses, la signification change:
#double 1+2;; - : int = 4
Sans parenthèses, l'argument est interprété différemment (ici
comme la soustraction de double et 1):
#double -1;; Entrée interactive: >double -1;; >^^^^^^ Cette expression est de type int -> int, mais est utilisée avec le type int.
En Caml, les priorités des opérateurs sont une généralisation des conventions des mathématiques pour les fonctions trigonométriques.
f x + g y
veut dire (f x) + (g y). Autrement dit les
arguments d'une opération s'étendent au maximum à droite et à gauche
de l'opération, comme si des parenthèses implicites apparaissaient à
droite et à gauche de l'opérateur ( ... ) + ( ... ) .
sin x + cos x signifie (sin x) + (cos x).
sin x / cos x signifie (sin x) / (cos x).
sin x > cos x signifie (sin x) > (cos
x).
f x > g y signifie donc (f x) > (g y);
f x :: map f l signifie (f x) :: (map f l);
f x && g y signifie (f x) && (g y).
f (x + 1) pour appliquer f à
la somme de x et 1.
En revanche f x + 1 signifie (f x) + 1.
(Notez que la commutativité de l'addition, n + m = m + n,
permet d'écrire f x + 1 = 1 + f x, et
personne ne pourrait imaginer que 1 + f x signifie autre
chose que 1 + (f x).)f x+1 est compris comme
f x + 1, et signifie donc aussi (f x) + 1.
f (-1) pas f -1 qui signifie f - 1.)
sin (x + pi) car sin x + pi
signifie (sin x) + pi.
1 + x * x signifie 1 + (x * x)
x * x+1 signifie (x * x) + 1
1 + x * sin (x - 1) signifie 1 + (x * sin (x - 1))
x + y > z signifie donc (x + y) > z, pas
x + (y > z). De même
f x y > g z + h t signifie f x y > (g z + h
t). Ou encore
f x y > g z + h t && x + y = 1 signifie
(f x y > g z + h t) && (x + y = 1)
sin x + tan x > cos x signifie (sin x + tan x) > cos x
x * fact (x - 1) est analogue à x * sin (x - 1).
x * fact x - 1 est analogue à x * sin x - 1
et signifie donc x * (fact x) - 1.
let rec fact = function | 0 -> 1 | n -> n * fact (n - 1);;
let rec fib = function | 0 -> 1 | 1 -> 1 | n -> fib (n - 1) + fib (n - 2);;
let lettre = function | `a` .. `z` | `A` .. `Z` -> true | _ -> false;;
let lettre = function
| c when c >= `a` && c <= `z`
|| c >= `A` && c <= `Z` -> true
| _ -> false;;
On se sert de références pour définir des compteurs ou variables des
langages impératifs traditionnels. On définit la fonction factorielle
avec une boucle for et un accumulateur définit par une référence:
#let fact x = let res = ref 1 in for i = 1 to x do res := i * !res done; !res;; fact : int -> int = <fun> #fact 10;; - : int = 3628800
Définition:
#let v = [| 0; 1; 2 |];; v : int vect = [|0; 1; 2|] #let v1 = make_vect 3 0;; v1 : int vect = [|0; 0; 0|]Accès et modification:
#v.(0);; - : int = 0 #v.(0) <- 1;; - : unit = () #v;; - : int vect = [|1; 1; 2|]
Parcours:
#for i = 0 to vect_length v - 1 do print_int v.(i); print_string "; "; done;; 1; 1; 2; - : unit = ()
Définition:
#let l = [ 0; 1; 2 ];; l : int list = [0; 1; 2] #let l1 = 0 :: 1 :: 2 :: [];; l1 : int list = [0; 1; 2]
Accès: par filtrage:
#match l1 with | x :: rest -> x | [] -> failwith "vide: impossible";; - : int = 0
Pas de modification physique possible, mais on peut définir une fonction qui modifie un élément d'une liste:
let rec change n v = function | [] -> raise Not_found | x :: rest -> if n = 0 then v :: rest else x :: change (n - 1) v rest;; change : int -> 'a -> 'a list -> 'a list = <fun>
Parcours: on utilise des itérateurs prédéfinis. map pour
obtenir la liste des résultats de l'application d'une fonction.
do_list pour appliquer une procédure à tous les éléments
de la liste.
#let l1 = [4; 2];; l1 : int list = [4; 2] #do_list print_int l1;; 42- : unit = () #do_list (function i -> print_int i; print_string "; ") l1;; 4; 2; - : unit = ()
Contacter l'auteur Pierre.Weis@inria.fr