Author: Christian.Queinnec@lip6.fr

## Entrées-sorties

Les fonctions d'entrées-sorties calculent une valeur (souvent de type unit), mais durant ce calcul elles effectuent une modification de l'état des périphériques d'entrées-sorties : modification du buffer du clavier, affichage à l'écran, écriture dans un fichier ou modification du pointeur de lecture. Les deux types suivants sont prédéfinis : in_channel et out_channel pour respectivement les canaux d'entrées et de sorties. Quand une fin de fichier est rencontrée l'exception `End_of_file` est déclenchée. Enfin, les trois constantes suivantes correspondent aux canaux standard d'entrée, de sortie et d'erreur à la manière d'Unix : `stdin`, `stdout` et `stderr`.

### Canaux

Les fonctions d'entrées-sorties de la bibliothèque standard d'Objective CAML manipulent des canaux de communication : valeurs de types in_channel ou out_channel. En dehors des trois valeurs standard prédéfinies, la création d'un canal utilise une des fonctions suivantes :

    # open_in;;
    - : string -> in_channel = <fun>
    # open_out;;
    - : string -> out_channel = <fun>

`open_in` ouvre le fichier s'il existe2, déclenche l'exception `Sys_error` sinon.
`open_out` crée le fichier indiqué s'il n'existe pas ou l'écrase s'il existe.

    # let ic = open_in "koala";;
    val ic : in_channel = <abstr>
    # let oc = open_out "koala";;
    val oc : out_channel = <abstr>

Les fonctions de fermeture des canaux sont :

    # close_in ;;
    - : in_channel -> unit = <fun>
    # close_out ;;
    - : out_channel -> unit = <fun>

### Lecture et écriture

Les fonctions les plus générales de lecture et d'écriture sont les suivantes :

    # input_line ;;
    - : in_channel -> string = <fun>
    # input ;;
    - : in_channel -> string -> int -> int -> int = <fun>
    # output ;;
    - : out_channel -> string -> int -> int -> unit = <fun>

- input_line`` ic : lit sur un canal d'entrée `ic` tous les caractères jusqu'au premier retour chariot ou la fin de fichier, et les rend sous la forme d'une chaîne de caractères (le retour chariot exclu).
- input`` ic`` s`` p`` l : tente de lire `l` caractères sur un canal d'entrée `ic`, et les stocke dans la chaîne `s` à partir du `p`ieme caractère. Le nombre de caractères effectivement lus est retourné.
- output`` oc`` s`` p`` l : écrit sur un canal de sortie `oc` une partie de la chaîne `s` commençant en `p`-ième caractère de longueur `l`.

Les fonctions suivantes lisent sur l'entrée standard ou écrivent sur la sortie standard :

    # read_line ;;
    - : unit -> string = <fun>
    # print_string ;;
    - : string -> unit = <fun>
    # print_newline ;;
    - : unit -> unit = <fun>

D'autres valeurs de type simple peuvent être aussi directement lues ou affichées. Ce sont les valeurs des types convertibles en chaînes de caractères.

##### Déclarations locales et ordre d'évaluation

Nous pouvons simuler une suite d'affichages des expressions de la forme let x = e1 in e2. Sachant que, en général, `x` est une variable locale susceptible d'être utilisée dans e2, nous savons que e1 est évaluée en premier et qu'ensuite vient le tour d'e2. Si les deux expressions sont des fonctions impératives dont le résultat est () mais qu'elles ont eu des effets de bord, nous les avons alors exécutées dans le bon ordre. En particulier puisque nous connaissons la valeur de retour de e1 : la constante () de type unit, on obtient une séquence d'affichage en écrivant la suite de déclarations par filtrage du motif ().

    # let () = print_string "et un," in
     let () = print_string " et deux," in
     let () = print_string " et trois" in
        print_string " zéro";;
    et un, et deux, et trois zéro- : unit = ()

### Exemple : C+/C-

L'exemple suivant implante le jeu << C'est plus/C'est moins >> qui consiste à cacher un nombre qu'un utilisateur devra trouver. Le programme indique à chaque réponse si le nombre caché est plus petit ou plus grand que le nombre proposé.

    #  let rec cpcm n =
         let () = print_string "taper un nombre : " in
         let i = read_int ()
         in
           if i = n then
             let () = print_string "BRAVO" in
             let () = print_newline ()
             in print_newline ()
           else
             let () =
               if i < n then
                 let () = print_string "C+"
                 in print_newline ()
               else
                 let () = print_string "C-"
                 in print_newline ()
             in cpcm n ;;
    val cpcm : int -> unit = <fun>

Voici un exemple de session :

    # cpcm 64;;
    taper un nombre : 88
    C-
    taper un nombre : 44
    C+
    taper un nombre : 64
    BRAVO

    - : unit = ()