Tout d'abord une petite erreur d'exécution : un read_int()
demande un entier à l'utilisateur. Que se passe-t-il si celui-ci tape autre chose qu'une valeur entière ? Testons cela :
let x = read_int() in print_int x;
Vous pouvez essayer de taper des lettres (comme "blabla"
), ou bien un nombre réel (par exemple "3.14"
), ou n'importe quelle autre séquence de caractères qui ne représente pas un entier, et vous obtiendrez l'affichage :
Fatal error: exception Failure("int_of_string")
Il y a eu une "Erreur fatale"
dans le traitement nommé "int_of_string"
, traduire "Nombre entier à partir d'un texte"
. Cela veut simplement dire que le programme n'a pas su comment traduire le texte que l'utilisateur a donné en un nombre entier correct.
Une erreur fréquente est la mise d'un point-virgule à la place d'un in
. Pour des raisons que l'on comprendra plus tard, le compilateur n'est pas capable de détecter proprement une telle erreur. Le message d'erreur obtenu est variable selon les cas.
Lorsque l'erreur est localisée sur la ligne du let
en question, on s'aperçoit rapidement du problème. Mais ce n'est pas toujours le cas, et il est tout à fait possible que le compilateur indique une erreur de syntaxe plus loin dans le source. Lorsqu'on obtient une erreur de syntaxe déroutante, le mieux est de relire tranquillement le code du début à la fin, en vérifiant les in
et les points-virgules.
Voici un cas possible :
let x = 5; print_int x;
File "test.ml", line 1, characters 8-9: Warning: this expression should have type unit. File "test.ml", line 2, characters 10-11: Unbound value x
On n'a pas les moyens de trop comprendre la première phrase, mais la seconde est claire : Unbound value x
qui se traduit : x
n'est pas défini. On en déduit qu'il doit y avoir une erreur dans sa déclaration.
Dans read_int()
, et aussi dans print_newline()
, il n'y a pas besoin d'espace entre le mot et le couple de parenthèses. Toutefois, ce n'est pas une erreur d'en mettre un comme dans "read_int ()"
. Par contre l'oubli du couple de parenthèses à la fin de read_int()
est une erreur :
let mon_nombre = read_int in print_int mon_nombre; print_newline();
File "test.ml", line 2, characters 10-20: This expression has type unit -> int but is here used with type int
Contrairement aux messages d'erreurs que nous avons vues auparavant, il ne s'agit pas d'une erreur de syntaxe, mais d'une erreur de type. Le type d'une valeur, c'est sa nature. Ainsi le type de 5 est "entier"
, ce qui se dit int
(comme abréviation de integer
). Le texte "blabla"
est de type "string"
(pour "chaîne de caractère"
). Il y a beaucoup d'autres types, et on aura l'occasion d'en voir d'autres plus tard. Essayons pour l'instant d'apprendre une méthode permettant d'analyser les messages d'erreurs de type.
L'erreur se situe à la ligne 2, sur le texte mon_nombre
. Le compilateur nous dit qu'il pensait que mon_nombre
était du type unit -> int
, que l'on lit "unit donne int"
. Cela n'est pas en accord avec l'utilisation que l'on souhaite faire de mon_nombre
à la ligne 2 : puisque print_int
permet d'afficher un entier, mon_nombre
devrait être de type int
(entier). Nous ne sommes pas à ce point en mesure de comprendre le sens de unit -> int
, mais ce dont nous sommes sûrs, c'est que ce n'est pas le type int
. On comprend qu'il y a donc une erreur dans la définition de mon_nombre
, ce qui nous permet de retrouver l'oubli des parenthèses.
On a dit tout à l'heure que l'utilisation du let
était obligée lors du read_int
, car on avait besoin d'utiliser la valeur donnée par read_int()
plusieurs fois. Lorsqu'on ne souhaite l'utiliser qu'une seule fois, il est possible de l'utiliser directement. Ainsi le code suivant demande un entier à l'utilisateur, et l'affiche tout de suite après ;
print_int (read_int());
Mais cette présentation réduit la lisibilité, et pourra en plus poser des problèmes par la suite, donc on appliquera la règle :
Pour demander des données à l'utilisateur, on en posera toujours la valeur avec un let
.
On sait demander un entier à l'utilisateur. Voyons maintenant comment lui demander du texte. Pour demander à l'utilisateur une ligne de texte, on utilise la commande read_line()
, traduction "lire une ligne"
. Cette commande s'utilise de la même manière que read_int()
.
read_line()
permet de demander à l'utilisateur une ligne de texte.
Remarque : on peut se demander pourquoi la commande n'est pas nommée read_string()
. Comme on le verra plus tard, une string
peut contenir plusieurs lignes de textes, alors que la commande qu'on utilise ici ne permet de lire qu'une seule ligne à la fois. En effet, pour écrire plusieurs lignes, il faudrait utiliser la touche entrée, mais ici cette touche sert à terminer la saisie du texte.