Next: Blocs et portée des
Up: Quelques éléments de Caml
Previous: Types de base
Les expressions arithmétiques font intervenir les opérateurs classiques sur les entiers + (addition), - (soustraction), * (multiplication), / (division entière), mod (modulo). On utilise les parenthèses comme en mathématiques. Ainsi, si x et y sont deux entiers, on écrit 3 * (x + 2 * y) + 2 * x * x pour 3 (x + 2y) + 2 x2.
Les mêmes opérateurs, suffixés par un point, servent pour les expressions flottantes. Donc, si z est un flottant, on écrit 3.0 *. (z +. 1) /. 2.0 pour 3 (z+1) / 2. Les fonctions int_of_float et float_of_int autorisent les conversions des flottants dans les entiers: la première donne la partie entière, la seconde convertit un entier en flottant. Contrairement à Pascal ou à C, les conversions ne sont jamais automatiques: par exemple 3.5 + 2 est toujours mal typé.
En Caml, les conversions sont explicites.
Une expression conditionnelle ou alternative s'écrit:
if {\em $e$} then {\em $e_1$} else {\em $e_2$}
où la condition e est une expression booléenne du type bool, et e1, e2 sont deux expressions de même type qui est celui du résultat.
Les expressions booléennes sont construites à partir des opérateurs ||, &&, not, des booléens et des opérateurs de comparaison. Ainsi, si b et c sont deux identificateurs de type bool, l'expression
(b && not c) || (not b && c)
représente le ou-exclusif de b et c. Les deux opérateurs || et && se comportent exactement comme une construction ``if then else''. Par définition, a && b signifie if a then b else false et a || b signifie if a then true else b. Parfois ces opérateurs rendent un résultat sans évaluer certains de leurs arguments. Si a s'évalue en faux, alors a && b rend false sans que l'expression b soit évaluée.
Les opérateurs de comparaison =, <>, <=, <, >, >= rendent aussi des valeurs booléennes. On peut comparer des entiers, des flottants, des booléens, des caractères (dans ce dernier cas, l'ordre est celui du code ASCII) et même deux valeurs quelconques, pourvu qu'elles soient du même type.
La précédence des opérateurs est naturelle. Ainsi * est plus prioritaire que +, lui-même plus prioritaire que =. Si un doute existe, il ne faut pas hésiter à mettre des parenthèses. De manière générale, seules les parenthèses vraiment significatives sont nécessaires. Par exemple, dans
if (x > 1) && (y = 3) then ...
la signification ne change pas si l'on ôte toutes les parenthèses. De même, dans l'expression du ou-exclusif
(b && not c) || (not b && c)les parenthèses sont superflues. En effet les précédences respectives de &&, || et not sont analogues à celles de *, + et -. On écrit donc plus simplement b && not c || not b && c. (Encore plus simple: b <> c!) Évidemment, certaines parenthèses sont impératives pour grouper les expressions. L'exemple des arguments de fonctions est plus particulièrement fréquent: comme en mathématiques f (x + 1) est essentiellement différent de f (x) + 1. Et comme on omet souvent les parenthèses autour des arguments très simples (variables ou constantes), il faut aussi noter que f (x) + 1 est synonyme de f x + 1. De toutes façons, les parenthèses sont indispensables pour les arguments de fonctions compliqués. Pour la même raison les parnthèses sont nécessaires autour des arguments négatifs f (-1) f -1, car f -1 est synonyme de f - 1 qui est une soustraction.
f (x + 1) f x + 1.
L'ordre d'évaluation des opérateurs dans les expressions respecte les conventions mathématiques lorsqu'elles existent (priorité de l'addition par rapport à la multiplication par exemple). En ce qui concerne l'application des fonctions, on évalue les arguments avant de rentrer dans le corps de la fonction (appel par valeur). Comme en C, il n'y a pas d'appel par référence mais on peut pratiquement le simuler en utilisant des références (c'est le cas pour la fonction decr décrite page ). L'ordre d'évaluation des arguments des opérateurs et des fonctions n'est pas spécifié par le langage. C'est pourquoi il faut impérativement éviter de faire des effets dans les arguments de fonctions. En règle générale, il ne faut pas mélanger les effets (impressions, lectures ou modification de la mémoire, déclenchement d'exceptions) avec l'évaluation au sens mathématique.En Caml, l'ordre d'évaluation des arguments n'est pas spécifié.
L'opérateur d'égalité s'écrit avec le symbole usuel =. C'est un opérateur polymorphe, c'est-à-dire qu'il s'applique sans distinction à tous les types de données. En outre, c'est une égalité structurelle, c'est-à-dire qu'elle parcourt complètement ses arguments pour détecter une différence ou prouver leur égalité. L'habitué de C peut être surpris, si par mégarde il utilise le symbole == au lieu de =, car il existe aussi un opérateur == en Caml (et son contraire !=). Cet opérateur teste l'égalité physique des valeurs (identité des adresses mémoire en cas de valeurs allouées). Deux objets physiquement égaux sont bien sûr égaux. La réciproque n'est pas vraie:
#"ok" = "ok";; - : bool = true #"ok" == "ok";; - : bool = false
L'égalité physique est indispensable pour comparer directement les références, plutôt que leur contenu (ce que fait l'égalité structurelle). On s'en sert par exemple dans les algorithmes sur les graphes.
#let x = ref 1;; x : int ref = ref 1 #let y = ref 1;; y : int ref = ref 1 #x = y;; - : bool = true #x == y;; - : bool = false #x == x;; - : bool = true #x := 2;; - : unit = () #x = y;; - : bool = false
1/11/1998