Ce chapitre précise le principe des expressions. Les expressions, c'est la vision que le compilateur a du code qu'on a écrit. Pour le compilateur, l'intégralité du code est construit avec des expressions. Comprendre comment le code est interprété par le compilateur a deux intérêts. Le premier est de pouvoir comprendre les messages d'erreurs qu'on peut obtenir. Le second est de pouvoir comprendre précisément de quelle manière sera interprété le code que l'on écrit. Détaillons ces deux points.
Des messages d'erreurs, on en a déjà vu un bon nombre. Lorsque le compilateur n'arrive pas à décortiquer le code en expression, il nous renvoie de sympathiques erreurs de syntaxes (syntax error
), ou bien d'erreur de typage (this expression has type ... but is here used with type ...
). Lorsqu'on utilise des noms qui ne sont associés à rien, on a le unbound value
, facile à corriger. Il y a encore des erreurs d'utilisation de fonctions. Lorsqu'on utilise une valeur comme une fonction : This expression is not a function, it cannot be applied
. Et lorsqu'on place plus d'arguments qu'il n'est censé en avoir : This function is applied to too many arguments
.
L'étude des expressions nous apportera aussi une compréhension nécessaire de certaines difficultés de la programmation. La première arrive lorsqu'on essaie d'associer une valeur à un nom qui est déjà associé à une autre valeur. On appelle cela la surdéfinition de variable. Une deuxième difficulté est la construction de valeurs avec des structures if
: on associe un nom à une valeur qui dépend d'un test. Troisième chose : connaître précisément le fonctionnement des expressions avec des &&
et des ||
du calcul booléen. En dernier, on s'intéressera aux fonctions.
Le principe de base est que chaque mot écrit dans le programme forme une expression, et que chaque expression est d'un et un seul type. On construit des expressions plus grande en groupant des petites expressions, puis des expressions encore plus grandes en regroupant ces grandes expressions, et ainsi de suite. A la fin, le code du programme tout entier forme une seule très grande expression. Avant de voir comment on peut construire de grandes expressions à partir de petites, il faut déjà commencer par voir les petites.
Les valeurs immédiates sont les plus courtes expressions. On connaît les entiers, les flottants, les caractères, et les booléens :
5
est une expression de typeint
.-4.67
est une expression de typefloat
.'c'
est une expression de typechar
.true
est une expression de typebool
.
Les références, les tableaux et les chaînes peuvent être construits à partir de ces valeurs immédiates :
ref 5
est une expression de typeint ref
.[| 3.4; 5.7; -2.34; 9.1 |]
est une expression de typefloat array
."super"
est une expression de typestring
.4 <> 5
est une expression de typebool
.
Remarques : une chaîne est une succession de caractères placés entre des guillemets. Autre remarque : on verra plus tard que le mot ref
est en fait le nom d'une fonction.
Un autre type est très utile:
Par définition, une expression qui réalise une action est de type unit
.
Dans ce contexte, ce mot veut simplement dire "action"
. Une telle expression n'a pas besoin d'être terminée par un point-virgule s'il n'y a rien après. En effet, le point-virgule ne sert qu'à séparer des expressions, comme on le précisera ensuite.
print_int 5
est une expression de typeunit
.print_float 3.14
est une expression de typeunit
.print_string "super"
est une expression de typeunit
.print_newline()
est une expression de typeunit
.
Remarque : ces expressions sont l'application d'une fonction avec des paramètres. Il s'agit donc déjà d'expressions construites à partir de petits bouts.
Deux expressions permettent de dire de ne rien faire :
begin end
est une expression de typeunit
.()
est une expression de typeunit
.
Avec des fonctions prédéfinies, on peut demander à l'utilisateur de fournir des valeurs. Par exemple : read_int
est une fonction de type unit -> int
. Lorsqu'on applique la fonction avec le paramètre ()
représentant le type unit
, ce qui donne read_int()
, on obtient une expression de type int
. Ainsi :
read_int()
est une expression de typeint
.read_float()
est une expression de typefloat
.read_line()
est une expression de typestring
.