Cours 1

Htmligure
Version & licenses
Creative Commons License

Premières expressions

Guyslain
Thursday, 21 July 2016

Retour au sommaire.

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.

Commentaires

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.

  1. (* Ceci est un (* commentaire *). Cette phrase est
  2. aussi dans le commentaire.
  3. *)

Expressions simples et types simples

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.

Expressions arithmétiques

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

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 :

  • hexadécimales 0x123abc,
  • octal 0o12345670,
  • binaire 0b1001101.

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 flottants

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 :

  • max_float le plus grand flottant exprimable,
  • min_float le plus petit flottant exprimable (négatif),
  • epsilon_float le plus petit flottant strictement positif,
  • nan not a number,
  • infinity.

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.

Opérateurs

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 :

  1. 23 / 3 (* cette expression vaut 7 *)

  2. 23 mod 3 (* cette expression vaut 2 *)

  3. 12 mod 4 (* cette expression vaut 0 *)

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.

Expressions booléennes

OCaml définit nativement un type pour les booléens, le type bool. Il existe exactement deux littéraux booléens :

  • true,
  • false.

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 :

  1. false || (true || not (true && not false))

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 :

  1. if boolean_expression then
  2. expression_if_true
  3. else
  4. expression_if_false

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 :

  1. if true then 4 else 5.

car 4 et 5. ne sont pas du même type (le premier est de type int, le second de type float).

Caractères et chaînes de caractères

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.

  1. 'f' (* le caractère f *)

  2. "hello world!" (* une chaîne de caractère *)

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.

  1. int_of_char 'a' (* l'entier correspondant au caractère a *)

  2. (* le 4e caractère après a, donc le caractère e : *)
  3. char_of_int (int_of_char 'a' + 4)

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.

Récapitulatifs

Nous pouvons maintenant utiliser OCaml comme une calculatrice. Nous avons appris la syntaxe des expressions simples, et les types de bases d'OCaml.

Tests

Retour au sommaire.