Logo de kxs.frCours d'informatique pour le lycée et la prépa

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 :

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];; : procedure avec effet de bord
  • let first s = s.[0];; : fonction sans effet de bord
  • let 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;;