• Aucun résultat trouvé

Fonctions de recherche dans les listes

Fonctionnelles et polymorphisme

7.3 Fonctions de recherche dans les listes

Les r´eponses toutes faites de Cam´elia sont stock´ees dans des listes d’une forme particuli`ere, les listes d’association, qui associent des r´eponses `a certains mots de la phrase du patient.

Appartenance d’un ´el´ement `a une liste

Nous commen¸cons par ´ecrire la fonction membre, qui d´etermine si son premier ar- gument est ´el´ement d’une liste donn´ee en second argument. Travaillant sur des listes, la fonction membre doit par cons´equent envisager les deux cas possibles de listes ; d’o`u le squelette de fonction :

let membre e = function | [] -> ...

| x :: reste -> ... ;;

Le cas de la liste vide est simple : l’´el´ement `a rechercher n’apparaˆıt certainement pas dans la liste.

let membre e = function | [] -> false

Fonctions de recherche dans les listes 131 Dans le cas g´en´eral, il faut tester si e est ´egal `a la tˆete de la liste (x), sinon interroger r´ecursivement le reste de la liste. On obtient donc :

# let rec membre elem = function | [] -> false

| x :: reste -> x = elem || membre elem reste;; membre : ’a -> ’a list -> bool = <fun>

Listes d’association

Les listes d’association sont simplement des listes de paires o`u le premier ´el´ement de la paire est une cl´e et le second la valeur associ´ee `a la cl´e. (Pour les tenants de Bourbaki, c’est le graphe d’une fonction donn´ee en extension.) Par exemple, consid´erez une liste d’adresses. On associe au nom d’une personne son adresse :

# let adresses =

[("Pierre Caml","Domaine de Voluceau, 78153 Le Chesnay Cedex"); ("Xavier Light","45 rue d’Ulm, 75005 Paris")];;

adresses : (string * string) list =

["Pierre Caml", "Domaine de Voluceau, 78153 Le Chesnay Cedex"; "Xavier Light", "45 rue d’Ulm, 75005 Paris"]

Dans notre programme, une liste d’association donnera les r´eponses possibles associ´ees aux phrases tr`es simples. Voici un extrait de la liste d’association des phrases simples :

let r´eponses_aux_phrases_simples = [([],

[|"Voulez-vous changer de sujet?"; "Continuez"|]); (["et"; "alors"],

[|"Alors expliquez-moi"; "Ne soyez pas si agressif"|]); (["non"],

[|"C’est vite dit"; "Pourriez-vous pr´eciser ?"|]); (["oui"],

[|"C’est un peu rapide"; "Donnez-moi plus de d´etails"|])];;

Cette liste associe `a la liste vide (correspondant `a une r´eponse vide) le tableau de r´eponses possibles [|"Voulez-vous changer de sujet?"; "Continuez"|]. Elle as- socie `a la phrase r´eduite `a et alors? les r´eponses [|"Alors expliquez-moi"; "Ne soyez pas si agressif"|]. Il nous faut donc retrouver la valeur associ´ee `a une phrase dans cette liste d’association. La fonction g´en´erale de recherche dans une liste d’association s’´ecrit tr`es simplement : on teste si la cl´e a ´et´e rencontr´ee, auquel cas on renvoie la valeur associ´ee ; sinon on cherche dans le reste de la liste. Si la liste est ´epuis´ee, il n’y a pas d’espoir de trouver la valeur associ´ee et l’on d´eclenche l’exception constante Pas_trouv´e.

# exception Pas_trouv´e;;

L’exception Pas_trouv´e est d´efinie. # let rec associ´e_de x = function

| [] -> raise Pas_trouv´e | (cl´e, valeur) :: l ->

if x = cl´e then valeur else associ´e_de x l;; associ´e_de : ’a -> (’a * ’b) list -> ’b = <fun>

# associ´e_de "Pierre Caml" adresses;;

- : string = "Domaine de Voluceau, 78153 Le Chesnay Cedex" # associ´e_de "Xavier Light" adresses;;

- : string = "45 rue d’Ulm, 75005 Paris" # associ´e_de "G´erard Coq" adresses;; Exception non rattrap´ee: Pas_trouv´e

Cette fonction est pr´ed´efinie en Caml sous le nom de assoc. En cas d’´echec, elle d´eclenche toujours une exception. Dans le syst`eme Caml Light c’est l’exception Not_found (signifiant « pas trouv´e » en anglais). C’est souvent l’exception d´eclench´ee par les fonctions de recherche de la biblioth`eque Caml Light.

Des listes d’association multi-cl´es

Pour les besoins de notre programme nous devons g´erer des listes d’association plus compliqu´ees que des listes (cl´e, valeur). En effet, nous consid´erons que certains mots

«int´eressants » sont synonymes et donc que leurs r´eponses associ´ees sont les mˆemes. Par exemple, ordinateur et machine appellent les mˆemes r´eponses. Le pluriel d’un mot est souvent trait´e comme le mot lui-mˆeme, par exemple ami et amis. Dans ces listes, une valeur n’est donc plus associ´ee `a une seule cl´e, mais `a une liste de cl´es ´equivalentes. Nous ´ecrivons donc la fonction qui teste si une cl´e donn´ee fait partie de la liste de cl´es et retourne en ce cas la valeur associ´ee :

# let rec associ´e_dans_liste cl´e = function | [] -> raise Pas_trouv´e

| (liste_de_cl´es, valeur) :: reste -> if membre cl´e liste_de_cl´es then valeur else associ´e_dans_liste cl´e reste;;

associ´e_dans_liste : ’a -> (’a list * ’b) list -> ’b = <fun>

De la mˆeme mani`ere, nous avons besoin de chercher, parmi une liste de cl´es la valeur associ´ee `a la premi`ere cl´e qui figure dans les cl´es d’une liste d’association (listes de cl´es, valeur). Nous parcourons donc la liste de cl´es argument en cherchant l’associ´e de la premi`ere cl´e rencontr´ee. S’il n’y a pas d’associ´e `a cette cl´e, nous cherchons, parmi le reste de la liste de cl´es argument, la premi`ere cl´e qui ait un associ´e dans la liste d’association. Remarquez au passage que le caract`ere ’ est autoris´e dans les noms d’identificateur en Caml.

# let rec associ´e_d’un_´el´ement_de liste_de_cl´es liste_d’association = match liste_de_cl´es with

| [] -> raise Pas_trouv´e | cl´e :: reste ->

try

associ´e_dans_liste cl´e liste_d’association with Pas_trouv´e ->

associ´e_d’un_´el´ement_de reste liste_d’association;;

Traitements de chaˆınes de caract`eres 133