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