Nous écrivons les premières expressions en OCaml et leurs types. OCaml dispose d'un interpréteur interactif, appelé toplevel, s'utilisant comme une calculette sophistiquée. On le lance avec la commande ocaml en console, ou utop, une version plus pratique, si elle est installée. Pour évaluer une expression dans le toplevel, il faut la terminer avec ;; avant d'appuyer sur entrée, cela signale au toplevel que l'expression est entièrement écrite.
Les commentaires s'écrivent entre des balises (* et *). On peut imbriquer les commentaires les uns dans les autres. Les commentaires peuvent s'étendre sur plusieurs lignes.
Nous commençons par l'étude des types simples, que nous distinguons des types composés qui se construisent à partir des types simples, par exemple pour construire les types des fonctions. Les types simples et les littéraux sont les briques élémentaires des programmes fonctionnels, que nous apprendrons à combiner pour créer des programmes complexes.
OCaml propose deux types par défaut pour les nombres, le type int pour les entiers, et le type float pour les flottants.
Les entiers qui ont le type int sont signés avec une précision fixe, il existe un entier maximum (nommé max_int, environ $2^{30}$ ou $2^{62}$ selon l'architecture de la machine), et un entier minimum. Il n'y a pas de dépassement de capacité pour les entiers, si un calcul dépasse cette limite, le résultat est calculé modulo un grand entier.
On peut écrire directement un entier par une suite de chiffres décimaux. Il existe aussi des syntaxes pour écrire les entiers dans d'autres bases :
Dans tous les cas, on peut commencer l'entier par un signe - pour exprimer un entier négatif, et on peut utiliser le caractère _ comme séparateur de blocs de chiffres pour améliorer la visibilité, typiquement par blocs de 3 chiffres comme dans 1_234_321 (un million deux cent trente quatre mille trois cent vingt-et-un).
Les nombres flottants, de type float, permettent de coder des nombres à virgule flottante, ils implémentent la norme IEEE 754 , ce sont donc les mêmes que dans la plupart des autres langages. Pour les distinguer des littéraux entiers, les littéraux flottants doivent contenir soit un point . (codant la virgule), soit un symbole e (ou E) d'exposant. La mantisse et l'exposant peuvent chacun avoir un signe -, l'exposant peut sinon prendre un signe +. Plusieurs valeurs spéciales sont définies :
On peut aussi utiliser _ dans la mantisse ou l'exposant pour créer des blocs de chiffres.
Il n'y a jamais de conversion implicite entre entiers et flottants, on n'a donc pas le droit de mélanger entiers et flottants dans les expressions.
Les deux types supportent les opérations arithmétiques usuelles : addition, soustraction, multiplication et division. Par contre, on n'additionne pas de la même façon les entiers et les flottants, il y a donc deux additions différentes. Et de même pour les autres opérations arithmétiques. Puisque tout expression n'a qu'un seul type, il faut deux expressions, deux notations différentes pour les deux additions. Les opérations sur les entiers sont donc +, -, * et /, et sur les flottants +., -., *. et /.. On retrouve donc le point de la virgule flottante dans la notation des opérateurs arithmétiques des flottants.
Les opérateurs s'utilisent en notation infixe, et les règles de priorité des opérateurs sont implémentés par OCaml. On peut bien sûr utiliser des parenthèses si nécessaire : de façon générale toutes les expressions en OCaml peuvent être parenthésées au besoin : les parenthèses servent à parenthèser !
La division pour les entiers est la division Euclidienne, donnant le résultat entier (le quotient). Pour obtenir le reste d'une division entière, on utilise mod, par exemple :
Les opérateurs entiers attendent une expression du type entier en membre droit et une expression de type entier en membre gauche. Une expression ainsi formée (membre droit de type int, opérateur entier, membre gauche de type int) est alors de type int. C'est la règle de typage pour les opérateur entier.
Les opérateurs flottants obéissent à une règle similaire, en remplaçant int par float partout.
Les opérateurs sont aussi des expressions, ils possèdent donc aussi un type. Comme un opérateur est en fait une fonction, ils ont un type de fonction, comme nous le verrons un peu plus tard. Leur règle de typage n'est en fait qu'un cas particulier de la règle de typage de l'application d'un fonction à un argument.
OCaml définit nativement un type pour les booléens, le type bool. Il existe exactement deux littéraux booléens :
Les booléens viennent avec leurs opérateurs binaires && (et, conjonction), || (ou, disjonction), et un opérateur unaire not qui s'utilise en position préfixe. Voici un exemple d'expression booléenne :
Les opérateurs binaires booléens obéissent à une règle de typage similaire à celle des opérateurs arithmétiques. L'opérateur unaire not prend un argument de type booléen, et l'expression ainsi formée a le type bool.
On rencontre souvent les booléens lors de comparaisons ou de test d'égalité de deux valeurs. Les opérateurs de comparaisons sont <, <=, >=, >, l'opérateur d'égalité est =. Attention, == n'est pas l'opérateur d'égalité, c'est bien un opérateur booléan, mais il fait autre chose (nous n'en aurons jamais besoin). Après tout, il n'y a pas de raisons de noter l'égalité avec un symbole autre que celui de l'égalité.
Ces opérateurs de comparaisons ont pour règles de typage : les deux termes doivent avoir le même type (peu importe lequel), alors le résultat de l'opérateur est un booléen.
Les expressions booléennes servent principalement à exprimer des expressions conditionnelles. En OCaml, l'expression conditionnelle s'exprime avec la syntaxe :
On notera bien comment l'expression est indentée pour refléter sa structure, cette indentation n'est pas requise par le compilateur, mais elle est requise par le cerveau humain pour être comprise plus facilement. Elle sera obligatoire pendant toute la durée du cours.
Les expressions conditionnelles définissent toujours les deux cas : si la condition est vraie et si la condition est fausse. En effet, l'expression doit prendre une valeur (principe : toute expression a une valeur), même si la condition est fausse. Donc la branche else doit être définie.
L'expression booléenne doit bien évidemment avoir le type bool. Les expressions expression_if_true et expression_if_false peuvent avoir n'importe quel type, du moment que c'est le même ! En effet, le type de l'expression conditionnelle complète est le type de la valeur prise lorsque cette expression est évaluée. Comme cela peut aussi bien être l'un ou l'autre des deux cas, et que l'expression conditionnelle ne peut avoir qu'un seul type (principe : tout expression a un et un seul type), l'expression conditionnelle a le même type que ses deux branches, qui ont donc le même type. Ainsi, l'expression suivante n'est pas bien typée :
car 4 et 5. ne sont pas du même type (le premier est de type int, le second de type float).
OCaml propose aussi les types char et string, respectivement pour les caractères et les chaînes de caractères. Les littéraux caractères sont notés entre guillemets simples, les chaînes de caractères entre guillemets doubles.
Les subtilités usuelles sur l'échappement des caractères spéciaux existent aussi en OCaml. Le caractère d'échappement est \.
On peut convertir les caractères vers un code entier avec la fonction int_of_char et réciproquement avec la fonction char_of_int. Les lettres (minuscules ou majuscules) ont des codes successifs respectant l'ordre alphabétique, ce qui permet de calculer le code de n'importe quelle lettre à partir du code de 'a'par exemple.
Les chaînes de caractères ont un opérateur binaire de concaténation noté ^. Il obéit une règle de typage similaire à celles des opérateurs arithmétiques.
Nous pouvons maintenant utiliser OCaml comme une calculatrice. Nous avons appris la syntaxe des expressions simples, et les types de bases d'OCaml.