Les bases de Caml
Les expressions
Phrases en CAML
Une phrase ou requête peut occuper plusieurs lignes ; elle se termine par un double point-virgule ;;.
1+1;; phrase
: int = 2 évaluation
Le résultat de l’évaluation (quand elle a lieu !) de chaque phrase comporte trois indications :
– le nom de la variable globale qui vient d’être définie le cas échéant ou, à défaut, un simple tiret.
– le type du résultat.
– la valeur du résultat.
En résumé :
Ecriture d’une phrase phrase ;;
Evaluation d’une phrase nom : type = valeur ou – : type = valeur
Commentaires
Il est conseillé de placer des commentaires dans le code source ; un commentaire consiste en du texte, ignoré par l’interpréteur. Ce texte est donc exclusivement destiné à l’humain qui le lira. L’emploi de commentaires rend les sources d’un programme lisibles par un tiers (qui, bien souvent, est l’auteur quelques temps plus tard). Un commentaire se doit d’être concis, et ne consiste pas en un “plagiat” du code source : il doit éclairer ce dernier, préciser les sous-entendus ainsi que le principe de la méthode employée,…
Les délimiteurs de commentaires sont (* et *).
En résumé :
Insertion de commentaires (* … *)
Les identificateurs
Il est souvent utile de donner un nom au résultat d’un calcul effectué par Caml. Comme en mathématiques, on peut avoir besoin de « variables » globales et locales.
Identificateurs globaux
On parle aussi, en se conformant à l’usage, de variables globales, même si nous verrons que cette expression peut induire en erreur. Les identificateurs globaux sont conservés en mémoire, et donc utilisables dans l’intégralité du programme. Ils sont à réserver aux objets dont nous avons besoin tout au long de notre travail.
Pour introduire (ou définir, ou déclarer) un identificateur global, la syntaxe est :
let identificateur = valeur
Une telle définition est une liaison d’un identificateur (autrement dit d’un nom, d’une abréviation) à une valeur (qui devient ainsi identifiée), que l’on peut utiliser dans la suite de notre programme. C’est l’équivalent du « soit » en mathématiques, tel qu’employé dans l’expression « Soit M la borne supérieure de f sur [0; 1]. »
let y = 7 ;; (* 7 a pour nom y *)
y : int = 7
let successeur n = n + 1 ;;
successeur : int > int = <fun>
successeur y ; ; (* Caml sait qui est désigné par le symbole y *)
: int = 8 let y = 7 ;; y : int = 7 y + 2 ;;
: int = 9
Remarque : voici un point relativement compliqué. Il ne faut pas confondre cette définition de l’affectation. Une fois défini, un nom conserve la valeur donnée, à moins de le redéfinir, c’est pourquoi le terme de « variable » est plutôt à éviter dans ce cadre, et il vaut mieux parler d’identificateur.
let y = 7 ;; (* 7 a pour nom y *)
y : int = 7
let x = y + 2 ;; (* 7 + 2 a pour nom x *)
x : int = 9
let y = 2 ;; (* y n’ identifie plus 7 mais 2 *)
y : int = 2
x ;; (* x est toujours le nom de 9 *)
: int = 9
Pour une raison obscure, nous avons redéfini y. Nous pouvons même le redéfinir à partir de sa définition actuelle :
let y = 7 ;; (* 7 a pour nom y *)
y : int = 7
let y = y + 2 ;; (* 7+2 a pour nom y *)
y : int = 9
Cependant, cette programmation horrible est à proscrire, tant elle contrevient à l’esprit Caml. D’une manière générale, il ne semble pas opportun de redéfinir un identificateur.
Identificateurs locaux
Ce sont les identificateurs auxiliaires, permettant de réaliser et de donner un sens à un calcul secondaire : ce sont des définitions « jetables » (et « jetées »).
La syntaxe est la même que pour les identificateurs globaux, mais on lie la déclaration de l’identificateur local à l’expression dans laquelle il est utilisé par in :
let identificateur_local = valeur in expression
# let y = 7 in y + 2 ;;
: int = 9
# y ;; Toplevel input : >y ;;
>^
The value identifier y is unbound .
On peut aussi observer que cette phrase est une expression et non une déclaration.
On peut par ailleurs utiliser un identificateur local pour définir un identificateur global :
let x = (* x est global *) let y = 7 in (* y est local, et sert à définir x *) y + 2 ;; x : int = 9
x ;;
: int = 9 y ;; Toplevel input : >y ;;
>^
The value identifier y is unbound .
En reprenant l’analogie avec l’exemple de la somme en mathématiques, que se passe-t-il si nous avons la mauvaise idée d’utiliser un identificateur global pour identificateur local ?
let y = 3 ;;
y : int = 3
let x = let y = 7 in y + 2 ;;
x : int = 9
x ;;
: int = 9 y ;;
: int = 3
L’identificateur local l’a emporté au sein de l’expression à laquelle il est associé, ce qui est normal (à quoi servirait-il sinon ?). Bien sûr, il vaut mieux éviter cette réutilisation pour le moins maladroite.
Pour mieux insister sur le caractère secondaire d’un identificateur local, on peut inverser les ordres de la définition et de l’expression, en utilisant where au lieu de in, c’est-à-dire en écrivant :
expression where identificateur_local = valeur
On peut ainsi écrire :
# let x = y + 2 where y = 7 ;; x : int = 9
# x ;;
: int = 9
Remarque : dans la mesure du possible, on privilégiera les identificateurs locaux ; cela limitera les erreurs.
Afin d’éviter de trop nombreuses définitions emboitées, on pourra utiliser and pour introduire plusieurs identificateurs (qu’ils soient locaux ou globaux, et que ce soit avec in ou where) :
# x + y + z where z = 13 and x = 5 and y = 12 ; ; : int = 30