Unit
Définitions
unit
est un type qui ne contient qu'un seul élément : ()
.
Il signifie « rien », c'est un peu l'équivalent du NULL
en C ou du None
en Python.
Il est important de connaitre ce type car il peut être source de problèmes.
Pourquoi avoir choisi ()
?
Car lorsqu'une fonction n'a pas de paramètres, on l'appelle avec () qui correpond à « rien ».
Procédures
Nous avons déjà rencontré le type unit
avec la famille des fonctions print_
.
Ces fonctions ne renvoient pas de valeurs, elles se contentent d'afficher quelque-chose à l'écran.
On dit qu'elles sont à effet de bord car elles modifient un état en dehors de leur environnement local.
Une fonction qui fait autre chose que de renvoyer une valeur est une fonction à effet de bord.
On appelle procédure une fonction qui ne renvoie pas de valeur.
On nommera également instruction une expression qui ne renvoie pas de valeur.
Ainsi, une procédure sans effet de bord et complètement inutile !
Séquencement
Jusqu'à présent, nous avons utilisé des expressions renvoyant des valeurs, cela n'avait donc pas de sens d'écrire une suite d'expressions.
Or les instructions ne retournant pas de valeur il est possible de les écrire en séquence.
Pour cela, on les sépare par un point virgule ;
.
Par exemple :
# print_string "Bon";print_string "jou";print_string "r !";;
Bonjour !- : unit = ()
On peut essayer décrire une séquence d'expressions mais OCaml nous donnera alors un avertissement :
# 2+2;3+3;;
Line 1, characters 0-3:
Warning 10 [non-unit-statement]: this expression should have type unit.
- : int = 6
En effet, la première expression n'a pas de raison d'être là puisqu'elle est « perdue » car remplacée par la deuxième.
OCaml suggère alors de lui substituer une instruction de type unit
car il est possible de faire une séquence d'instruction et de terminer par une expression :
# print_string "Une instruction";"Une expression";;
Une instruction- : string = "Une expression"
Regroupement d'instructions
Il peut être parfois nécessaire de regrouper plusieurs instructions ensembles.
On peut alors utiliser des parenthèses ou begin… end
.
Les deux syntaxes sont équivalentes.
Par exemple :
# let rec ascii n =
if n<128 then (print_int n;print_char ':';print_char (Char.chr n);print_newline ();ascii (n+1))
else ()
est équivalent à :
# let rec ascii n =
let rec ascii n =
if n<128 then begin
print_int n;
print_char ':';
print_char (Char.chr n);
print_newline ();
ascii (n+1)
end
else ();;
Primitives avec effet de bord
Voici une liste de primitives (procédures de base) avec effet de bord :
print_string
: affiche une chaîne de caractèresprint_endline
: affiche une chaîne de caractères et passe à la ligneprint_int
: affiche un entierprint_char
: affiche un caractèreprint_float
: affiche un floatprint_newline
: effectue un saut de ligne (attend un paramêtre vide)Printf.printf
: fonctionne de la même manière qu'en C ! (%s : string, %c : caractère, %d : int)
Exercices
1) Pour les fonctions suivantes, dire si elles sont des procédures et si elles sont à effet de bord :
let first s = print_char s.[0];;
let first s = s.[0];;
let foo () = 2+6;print_string "";;
let first s = print_char s.[0];;
: procedure avec effet de bordlet first s = s.[0];;
: fonction sans effet de bordlet foo () = 2+6;print_string "";;
: procedure sans effet de bord -> inutile
2) Écrire une fonction qui affiche un compte à rebours du temps qu'il reste avant la fin du cours.
On lui donnera comme paramètre le nombre de secondes avant la fin du cours et la fonction devra afficher toutes les secondes le nombre de secondes restantes.
On pourra faire la même fonction avec des minutes.
Nous aurons besoin de Unix.sleep
pour l'attente et on utilisera Printf.printf
avec le marqueur « %! » à la fin pour forcer l'affichage.
# let rec fin_cours x =
if x = 0 then print_int 0
else (Printf.printf "%d\n%!" x;Unix.sleep 1;fin_cours (x - 1));;
3) Écrire une fonction récursive qui affiche une pyramide alignée à gauche d'une taille donnée en argument.
On doit pouvoir choisir le caractère composant la pyramide.
par exemple pyramide '*' 5 1;;
doit donner :
*
**
***
****
*****
let rec pyramide caractere niveaux niveau_actuel =
if niveau_actuel > niveaux then ()
else begin
print_endline (String.make niveau_actuel caractere);
pyramide caractere niveaux (niveau_actuel + 1)
end;;
(* Appel de la fonction *)
pyramide '*' 5 1;;