List.iteri et Array.iteri en OCaml

Note

Un petit article sur deux fonctions pratiques du langage OCaml.

Avis

Si le mot OCaml n'évoque rien pour vous, cet article ne vous intéressera pas !

List.iter et Array.iter

Ces deux fonctions sont des classiques des modules List [2] et Array [1].

Ces fonctions sont des itérateurs du type suivant :

val List.iter : ('a -> unit) -> 'a list -> unit
val Array.iter : ('a -> unit) -> 'a array -> unit

Elles permettent donc d'appliquer une fonction f : 'a -> unit qui agit par effets de bords (e.g., affichage) à chaque élément d'une liste (ou d'un tableau).

Pratique donc !

Une meilleure version ?

Mais... Souvent, on a besoin, en plus de la valeur x de chaque élément, de leur indice i (par exemple pour afficher "la case i contient x[i]" ou autre).

Donc, on aimerait aussi avoir des itérateurs du type suivant :

val List.iteri : (int -> 'a -> unit) -> 'a list -> unit
val Array.iteri : (int -> 'a -> unit) -> 'a array -> unit

Où désormais f prend en premier argument l'indice correspondant à son deuxième argument. Très pratique pour éviter les boucles for !

Note

En Python... ?

La syntaxe commune à tous les itérateurs permet d'éviter ça de toutes façons, e.g. :

for i in [2*i for i in range(8)]:
    print i

Et la fonction enumerate permet de faire ça aussi, en itérant sur i, xi.

Deux fonctions qui ont tardées à venir

On constate que si Array.iteri a été codée en 1997 [3], son équivalent pour les listes List.iteri n'a été ajoutée qu'en... 2010 avec OCaml v4.00.1 ! (cf [4]).

Quel est le problème ?

Ces fonctions sont assez pratiques, donc souvent utilisés.

Dans le cadre des projets et autre exercices demandés par certains cours à l'ENS Cachan, il faut faire marcher son code sur (au moins) une machine de la salle 411, qui sont vieilles !

C'est ainsi qu'en décembre 2013, nous avions perdu quelques minutes (durant un examen oral !) à trouver la source du problème, et inclure un petit "patch" v3.12 → v4.01.0 en ajoutant à la main le code de List.iteri dans nos projets [5].

En particulier, ce lien [6] montre les modifications effectuées sur mon code lors de la découverte de ce bug.

Bref, on aurait aimé les avoir plus tôt !

Voilà un titre qui résume bien le message (inutile) de ce petit post.


Références

[1]
Documentation:Array.iter dans la doc du module Array;
[2]
Documentation:List.iter dans la doc du module List;
[3]
Source:le diff pour array.ml qui a introduit Array.iteri (sur le svn de l'INRIA);
[4]
Source:le diff pour list.ml qui a introduit List.iteri (sur le svn de l'INRIA);
[5]
Voir:le rapport du projet Laby fait en décembre 2013 pour l'épreuve de modélisation de l'agrég;
[6]
Voir:le commit rapportant la compatibilité avec OCaml v3.12.1 pour mon projet Laby (privé).

Note

« Mais OCaml c'est nul non ? »

Non, faut pas écouter ceux qui disent ça, OCaml c'est super !