Précédent Index

Exemple d'utilisation des arbres généraux

 
 
Les arbres généraux permettent de représenter efficacement un système de fichiers comme il en existe sous Linux ou sous Windows. En effet, dans un tel système, des répertoires contiennent des fichiers et des répertoires qui contiennent à leur tour des fichiers et des répertoires qui...
 
 

 
Notion de descripteur de fichier  
Dans un tel système, fichiers et répertoires sont décrits à l'aide de descripteurs qui, dans la réalité, comportent le nom du fichier ou du répertoire, la date de création, la date de modification... ainsi que des informations pour situer le fichier sur le disque. Dans notre modèle, le descripteur ne comportera que les informations suivantes:  
Barrière d'abstraction Descripteur
 
Nous manipulerons les descripteurs à l'aide des fonctions suivantes:
 
;;;;;;;; Constructeurs  
;;; fichier : string * nat -> Descripteur 
;;; (fichier nom taille) rend le descripteur du fichier de nom «nom» et  
;;; de taille «taille» 
 
;;; repertoire : string -> Descripteur 
;;; (repertoire nom) rend le descripteur du répertoire de nom «nom» 
 

 
;;;;;;;; Reconnaisseurs  
;;; fichier? : Descripteur -> bool 
;;; (fichier? desc) rend #t ssi «desc» est le descripteur d'un fichier 
 
;;; repertoire? : Descripteur -> bool 
;;; (repertoire? desc) rend #t ssi «desc» est le descripteur d'un répertoire 
 

 
;;;;;;;; Accesseurs  
;;; nom : Descripteur -> string 
;;; (nom desc) rend le nom du répertoire ou du fichier dont le descripteur est «desc» 
 
;;; taille : Descripteur -> nat 
;;; ERREUR lorsque la description donnée est la description d'un répertoire 
;;; (taille desc) rend la taille du fichier dont le descripteur est «desc» 
 

 
Implantation de la barrière d'abstraction Descripteur
 
On peut implanter cette barrière d'abstraction en utilisant des vecteurs (de longueur deux pour les répertoires et 3 pour les fichiers):  
Remarque: dans notre exemple, les nombres d'informations à mémoriser étant différents pour les fichiers et pour les répertoires, le premier composant du vecteur est inutile. Nous avons tout de même préféré la solution donnée ci-dessus, car, dans le futur, on pourrait être amené à ajouter, dans notre modèle, une autre information pour les répertoires (par exemple, le nombre d'éléments qu'il contient).
 
L'implantation est alors très simple et nous ne la commenterons pas:
 
;;;;;;;; Constructeurs  
;;; fichier : string * nat -> Descripteur 
;;; (fichier nom taille) rend le descripteur du fichier de nom «nom» et  
;;; de taille «taille» 
(define (fichier nom taille)
  (vector 'F nom taille))
 
;;; repertoire : string -> Descripteur 
;;; (repertoire nom) rend le descripteur du répertoire de nom «nom» 
(define (repertoire nom)
  (vector 'D nom))

;;;;;;;; Reconnaisseurs  
;;; fichier? : Descripteur -> bool 
;;; (fichier? desc) rend #t ssi «desc» est le descripteur d'un fichier 
(define (fichier? desc)
  (equal? (vector-ref desc 0) 'F))
 
;;; repertoire? : Descripteur -> bool 
;;; (repertoire? desc) rend #t ssi «desc» est le descripteur d'un répertoire 
(define (repertoire? desc)
  (equal? (vector-ref desc 0) 'D))

;;;;;;;; Accesseurs  
;;; nom : Descripteur -> string 
;;; (nom desc) rend le nom du répertoire ou du fichier dont le descripteur est «desc» 
(define (nom desc)
  (vector-ref desc 1))
 
;;; taille : Descripteur -> nat 
;;; ERREUR lorsque la description donnée est la description d'un répertoire 
;;; (taille desc) rend la taille du fichier dont le descripteur est «desc» 
(define (taille desc)
  (vector-ref desc 2))

 
Représentation d'un système de fichiers  
Un système de fichiers peut être représenté par un arbre général dont les étiquettes sont des descripteurs.
 
Noter que tout arbre ainsi défini ne représente pas un système de fichiers valide: dans un système de fichiers réel, tout noeud qui a comme étiquette un descripteur de fichier doit être une feuille et les noms des différents éléments d'un répertoire doivent être tous différents. Dans la suite, nous nommerons Systeme le type des éléments de ArbreGeneral[Descripteur] qui vérifient ces deux propriétés.
 
Définition de la fonction du-s  
Nous voudrions définir la fonction du-s qui correspond à la commande du -s d'Unix:
 
(du-s  (syst1))  ->  1111
 

 
;;; du-s : Systeme -> nat 
;;; (du-s systeme) rend la quantité d'espace disque utilisée par les fichiers du  
;;; système «systeme» 
 

 
Autrement dit, (du-s systeme) rend la somme des tailles de tous les fichiers présents dans le système. La définition de cette fonction est une définition « classique » pour les arbres généraux:  
 
(define (du-s systeme)
  (if (fichier? (ag-etiquette systeme))
      (taille (ag-etiquette systeme))
      (reduce + 0 (map du-s (ag-foret systeme)))))
 

 
Définition de la fonction ll  
Nous voudrions définir la fonction ll qui correspond à la commande ls -l d'Unix:
 
(ll  (syst1))  ->  
"
0       rab/
0       rgh/
66      fbc
"
 

 
;;; ll : Systeme -> Paragraphe 
;;; (ll systeme) rend le paragraphe contenant, pour chaque élément de «systeme» 
;;; (on ne considère que les sous-éléments immédiats), une ligne formée: 
;;; pour un fichier, de sa taille et de son nom (séparés par une tabulation), 
;;; pour un répertoire, de 0, d'une tabulation, de son nom immédiatement suivi  
;;; du caractère "/" 
 

 
Pour calculer le résultat de cette fonction, on peut:
  1. extraire la liste des descripteurs de tous les sous-arbres du système (en utilisant la fonctionnelle map appliquée à la forêt des sous-répertoires et à la fonction ag-etiquette),
  2. fabriquer la liste des lignes du paragraphe recherché (toujours à l'aide de la fonctionnelle map, appliquée à la liste des descripteurs obtenue dans le point précédent et à une fonction -- à définir -- qui rend la ligne pour un descripteur donné),
  3. et il n'y a plus qu'à fabriquer le paragraphe de toutes ces lignes.
 
Voici la définition Scheme correspondante:
 
(define (ll systeme)
  ;; desc-ll : Descripteur -> Ligne 
  ;; (desc-ll descripteur) rend l'image de «descripteur»: ligne formée: 
  ;; pour un fichier, de sa taille et de son nom (séparés par une tabulation), 
  ;; pour un répertoire, de 0, d'une tabulation, de son nom immédiatement suivi  
  ;; du caractère "/" 
  (define (desc-ll descripteur)
    (string-append 
     (->string (if (fichier? descripteur) 
                   (taille descripteur)
                   0))
     (string #\tab)
     (nom descripteur)
     (if (fichier? descripteur) "" "/")))
  ;; expression de (ll systeme) : 
  (paragraphe (map desc-ll 
                   (map ag-etiquette (ag-foret systeme)))))
 

 
Définition de la fonction find  
Nous voudrions définir la fonction find qui correspond à la commande Unix de même nom:
 
;;; find : string * Systeme -> Paragraphe 
;;; (find ident systeme) rend le paragraphe dont les lignes sont constituées par les noms  
;;; complets des fichiers ou répertoires du système «systeme» dont le nom est «ident». 
 

 
Voici un exemple de résultat de cette fonction:
 
(find "fbc" (syst1))  ->
"
./rab/rgh/fbc
./rab/fbc
./rcd/fbc
"
 

 
Comme il faut les noms complets, on doit définir une fonction auxiliaire qui a un argument de plus, une chaîne de caractères qui sera un préfixe des lignes de son résultat. De plus, comme d'habitude, pour les définitions de fonctions ayant un arbre généralisé comme donnée, il faut également définir une fonction qui a une forêt comme donnée. D'autre part, on peut noter que la valeur de l'argument « ident » (le nom à chercher) sera inchangée pour tous les appels récursifs: dans les deux fonctions auxiliaires précédentes, cet argument peut être mis en variable globale. D'où la structure de la définition de la fonction find:
 
(define (find ident systeme)
  ;; findAux : string * Systeme -> Paragraphe 
  ;; (findAux path systeme) rend le paragraphe dont les lignes sont constituées par les  
  ;; noms complets des fichiers ou répertoires du système «systeme» dont le nom est  
  ;; «ident», chaque ligne étant préfixée par «path». 
  ... à faire
  ... à faire
  ;; find-foret : string * Foret[Descripteur] -> Paragraphe 
  ;; (find-foret path F) rend le paragraphe obtenu en concaténant, pour tout arbre «A»  
  ;; de la fôret «F», (findAux path A) 
  ... à faire
  ... à faire
  ;; expression de (find ident systeme) : 
  (findAux "" systeme))
 

 
Définition de la fonction findAux
 
Le résultat de l'application de findAux est composé  
D'où la définition:
 
(define (find ident systeme)
  ;; findAux : string * Systeme -> Paragraphe 
  ;; (findAux path systeme) rend le paragraphe dont les lignes sont constituées par les  
  ;; noms complets des fichiers ou répertoires du système «systeme» dont le nom est  
  ;; «ident», chaque ligne étant préfixée par «path». 
  (define (findAux path systeme)
    (paragraphe-append
     (if (equal? ident (nom (ag-etiquette systeme)))
         (paragraphe (list (string-append path ident)))
         (paragraphe '()))
     (if (repertoire? (ag-etiquette systeme))
         (find-foret (string-append path (nom (ag-etiquette systeme)) "/")
                     (ag-foret systeme))
         (paragraphe '()))))
  ;; find-foret : string * Foret[Descripteur] -> Paragraphe 
  ;; (find-foret path F) rend le paragraphe obtenu en concaténant, pour tout arbre «A»  
  ;; de la fôret «F», (findAux path A) 
  ...
 

 
Définition de la fonction find-foret
 
Nous pouvons utiliser les fonctionnelles map et reduce, map permettant de fabriquer la liste des paragraphes résultats de la recherche sur les éléments de la forêt et reduce permettant de concaténer ces paragraphes.  
D'où la définition:
 
(define (find ident systeme)
  ;; findAux : string * Systeme -> Paragraphe 
  ;; (findAux path systeme) rend le paragraphe dont les lignes sont constituées par les  
  ;; noms complets des fichiers ou répertoires du système «systeme» dont le nom est  
  ;; «ident», chaque ligne étant préfixée par «path». 
  ... cf. ci-dessus
  ;; find-foret : string * Foret[Descripteur] -> Paragraphe 
  ;; (find-foret path F) rend le paragraphe obtenu en concaténant, pour tout arbre «A»  
  ;; de la fôret «F», (findAux path A) 
  (define (find-foret path F)
    ; findAux-path : ArbreGeneral[Descripteur] -> Paragraphe 
    ; (findAux-path G) rend (findAux path G) 
    (define (findAux-path G)
      (findAux path G))                             
    (reduce paragraphe-append (paragraphe '()) (map findAux-path F)))
  ...
 

 


Auteur(s): titou@ufr-info-p6.jussieu.fr.Mainteneur de la page: titou@ufr-info-p6.jussieu.fr.

Précédent Index