Programmation Fonctionnelle Avancée
Plan du cours : Zippers
ILe problème : naviguer efficacement une structure de données
ICe qui ne marche pas
ICe qui marche : les Zippers de Huet
IExemples
IComment dériver des Zippers pour tout type de données
IPour en savoir plus
Programmation Fonctionnelle Avancée
Manipulation efficace d’une structure de donnée arborescente
Description des objectifs
Naviguer dans une structure de données (en avant, et en arrière) :
Ien gardant la possibilité d’ajouter des valeurs au milieu
Isans faire de copies
Isans pointeurs arrières
Iet de façon efficace
Programmation Fonctionnelle Avancée
Manipulation efficace d’une structure de donnée arborescente
Premier essai
Des fonctions sur les listes avec position
(une l i s t e a ve c une p o s i t i o n e t une l o n g u e u r )
type a l i s t p o s = i n t int a l i s t ; ;
(c ha n ge r de p o s i t i o n , temps c o n s t a n t )
l e t agauche = f un c ti o n
( 0 ,_,_) > f a i l w i t h " de b u t ␣de l i s t e "
| ( p , t , l ) > ( p1, t , l ) ; ;
|| v a l agauche : i n t ’ a ’ b > i n t ’ a ’ b = <fun>
l e t a d r o i t e = fun c ti o n
( p , t , l ) when p=t > f a i l w i t h " f i n de l i s t e "
| ( p , t , l ) > ( p +1, t , l )
; ;
|| v a l a d r o i t e : i n t int ’ a > i n t int ’ a = <fun>
Programmation Fonctionnelle Avancée
Manipulation efficace d’une structure de donnée arborescente
Premier essai
Des fonctions sur les listes avec position
(i n s e r t i o n : temps l i n e a i r e )
l e t i n s e r t _ a t _ p o i n t x ( p , t , l ) =
l e t rec i n s =
fu n ct i on
( 0 , l ) > x : : l
| ( n , y : : r ) > y : : ( i n s ( n 1, r ) )
| _ >a s s e r t f a l s e
i n ( p , t +1 , i n s ( p 1, l ) ) ; ;
|| v a l i n s e r t _ a t _ p o i n t : a > i n t int a l i s t > i n t int a l i s t =
||
|| <fun>
Programmation Fonctionnelle Avancée
Manipulation efficace d’une structure de donnée arborescente
Premier essai
Des fonctions sur les listes avec position
(s u p p r e s s i o n : temps l i n e a i r e )
l e t d e l e t e _ a t _ p o i n t ( p , t , l ) =
l e t rec d e l =
fu n ct i on
( 0 , x : : l ) > l
| ( n , y : : r ) > y : : ( d e l ( n 1, r ) )
| _ >a s s e r t f a l s e
i n ( p , t 1, d e l ( p 1, l ) )
; ;
|| v a l d e l e t e _ a t _ p o i n t : i n t int a l i s t > i n t int a l i s t = <fun>
||
Programmation Fonctionnelle Avancée
Manipulation efficace d’une structure de donnée arborescente
Deuxième essai, non fonctionnel
Listes doublement chaînées
On peut essayer avec des références
t y p e ’ a d l l i s t = N i l | C e l l o f ’ a c e l l
and a c e l l = { i n f o : a ; n e x t : a d l l i s t ref ; p r e v : ’ a d l l i s t ref } ; ;
(d e p l a c e m e n t , t em p s c o n s t a n t )
let agauche =
function Nil > f a i l w i t h " L i s t e ␣ v i d e "
| C e l l { p r e v=c } when ! c = N i l > f a i l w i t h " D ej a a g auc he "
| C e l l { p r e v=c } > ! c ; ;
|| val ag a uc h e : a d l l i s t > a d l l i s t = <f u n >
(i n s e r t i o n , tem p s c o n s ta n t )
let i n s e r t a =
function Nil > C e l l { i n f o=a ; p re v=ref N i l ; n e x t= ref N i l }
| C e l l c a s d l l >
let c = C e l l { i n f o=a ; p re v=ref ! ( c . p r e v ) ; n e x t= ref d l l } i n
c . p r e v := c ; c
; ;
|| val i n s e r t : ’ a > a d l l i s t > a d l l i s t = <f u n >
Programmation Fonctionnelle Avancée
Manipulation efficace d’une structure de donnée arborescente
Deuxième essai, non fonctionnel
Listes doublement chaînées
Ce n’est pas idéal
Ifonctions d’impression du toplevel inutiles (les pointeurs arriere
font des cycles)
Iprogrammation penible et avec des effets de bord (la structure
de donnees n’est plus persistante)
Iil nous faut une idée !
Programmation Fonctionnelle Avancée
Manipulation efficace d’une structure de donnée arborescente
Zippers
Zipper de listes
Gérard Huet 1997
(un b l o c s u r l a p i l e c o n t i e n t j u s t e un a )
type a p i l e = a l i s t
type a l i s t z i p p e r = a p i l e a l i s t
exception Z i p p e r o f s t r i n g ; ;
l e t a_gauche : a l i s t z i p p e r > ’ a l i s t z i p p e r = function
| ( [ ] ,_) > r a i s e ( Z i p p e r " D ej a ␣ a␣ g au ch e " )
| ( a : : p , l ) > ( p , a : : l ) ; ;
|| val a_gauche : a l i s t z i p p e r > ’ a l i s t z i p p e r = <fun>
l e t a_ d r oi t e : a l i s t z i p p e r > a l i s t z i p p e r = function
| ( p , [ ] ) > r a i s e ( Z i p p e r " D ej a ␣ a d r o i t e " )
| ( p , a : : l ) > ( a : : p , l ) ; ;
|| val a _ d ro i t e : ’ a l i s t z i p p e r > ’ a l i s t z i p p e r = <fun>
Programmation Fonctionnelle Avancée
Manipulation efficace d’une structure de donnée arborescente
Zippers
Zipper de listes
l e t i n s e r t v : ’ a l i s t z i p p e r > ’ a l i s t z i p p e r = function
( p i l e , l i s t e ) > ( p i l e , v : : l i s t e ) ; ;
|| val i n s e r t : ’ a > a l i s t z i p p e r > a l i s t z i p p e r = <fun>
l e t d e l e t e : ’ a l i s t z i p p e r > ’ a l i s t z i p p e r = function
| ( p , [ ] ) > r a i s e ( Z ip pe r "Trop a d r o i t e ␣ pour ␣ e f f a c e r " )
| ( p , a : : r ) > ( p , r )
; ;
|| val d e l e t e : a l i s t z i p p e r > ’ a l i s t z i p p e r = <fun>
Programmation Fonctionnelle Avancée
Manipulation efficace d’une structure de donnée arborescente
Zippers
L’intuition derrière les zippers
Considérons une visite récursive d’une liste
l e t rec v i s i t = fu n ct i o n
|[] > ( )
| a : : r > v i s i t r
; ;
|| v a l v i s i t : a l i s t > u n i t = <fun>
Lors de la visite de [1;2;3;4], la valeur conservée sur la pile
d’appel, et la valeur du parametre évoluent comme suit :
[] [1;2;3;4]
[1] [2;3;4]
[2;1] [3;4]
[3;2;1] [4]
[4;3;2;1] []
Programmation Fonctionnelle Avancée
Manipulation efficace d’une structure de donnée arborescente
Zippers
L’intuition derrière les zippers, bis
En général
Un zipper représente explicitement l’état de la pile d’appel, et la
valeur courante, lors d’une visite récursive d’une structure de
données.
Ila pile d’appel est une suite de blocs d’activation
Ichaque bloc contient les éléments de la structure de données
qui ne sont pas passés à l’appel récursif, plus un marqueur
indiquant sur quel sous-structure on continue la visite
Dans le cas des listes, on n’a pas utilisé de marqueur, parce-que il y
a une seule soustructure pour continuer la visite.
Programmation Fonctionnelle Avancée
Manipulation efficace d’une structure de donnée arborescente
Zippers
Zipper des arbres binaires
type ’ a a r b r e = F e u i l l e
| Noeud of ’ a ’a arbre ’a arbre
type marqueur = Gauche | D r o i t e
type a b l o c k = m ar queu r ’ a a arbre
type a p i l e = a b l o c k l i s t
type ’ a a r b r e z i p p e r = ’ a p i l e a a r b r e ; ;
Programmation Fonctionnelle Avancée
Manipulation efficace d’une structure de donnée arborescente
Zippers
Zipper des arbres binaires
let bas_a_gauche : ’ a a r b r e z i p p e r > ’ a a r b r e z i p p e r =
function ( p i l e , a r b r e ) >match arbre w i t h
| Feuille > r a i s e ( Z i p p e r " F e u i l l e " )
| Noeud ( x , t1 , t 2 ) > ( Gauche , x , t 2 ) : : p i l e , t 1 ; ;
|| val bas_a_gauche : ’ a a r b r e z i p p e r > ’ a a r b r e z i p p e r = <f u n >
let bas_a_droi t e : ’ a a r b r e z i p p e r > ’ a a r b r e z i p p e r =
function ( p i l e , a r b r e ) >match arbre w i t h
| Feuille > r a i s e ( Z i p p e r " F e u i l l e " )
| Noeud ( x , t1 , t 2 ) > ( D r o i t e , x , t 1 ) : : p i l e , t 2 ; ;
|| val bas_a_droi t e : ’ a a r b r e z i p p e r > ’ a a r b r e z i p p e r = <fu n>
let en_haut : ’ a a r b r e z i p p e r > ’ a a r b r e z i p p e r =
function ( p i l e , a r b r e ) >match p i l e w i t h
| ( Gauche , x , t ) : : p > p , Noeud ( x , a r b r e , t )
| ( D r o i t e , x , t ) : : p > p , Noeud ( x , t , a r b r e )
| _ > r a i s e ( Z i p p e r " R ac i n e " ) ; ;
|| val en_haut : ’ a a r b r e z i p p e r > ’ a a r b r e z i p p e r = <f u n>
Programmation Fonctionnelle Avancée
Manipulation efficace d’une structure de donnée arborescente
Zippers
Zipper des arbres n-aires
type a n a r b r e =
| F e u i l l e of ’ a
| Noeud of a n a r b r e l i s t ; ;
type a b l o c k = a n a r b r e l i s t z i p p e r
type a p i l e = a b l o c k l i s t
type ’ a n a r b r e z i p p e r = a p i l e ’ a n a r b r e ; ;
Programmation Fonctionnelle Avancée
Manipulation efficace d’une structure de donnée arborescente
Zippers
Zipper des arbres n-aires
let a_gauche : ’ a n a r b r e z i p p e r > ’a narbrezipper =
function ( p i l e , a r b r e ) >match p i l e w i t h
| ( a : : lp , l ) : : p > ( lp , a r b r e : : l ) : : p , a
| ( [ ] ,_ ) : : p > r a i s e ( Z i p p e r " D ej a ␣a ␣ g au ch e " )
| _ > f a i l w i t h " Ra c in e " ; ;
|| val a_gauche : ’ a n a r b r e z i p p e r > ’a narbrezipper = <fun>
let a _ dr oi t e : ’ a n a r b r e z i p p e r > ’a narbrezipper =
function ( p i l e , a r b r e ) >match p i l e w i t h
| ( lp , a : : l ) : : p > ( a r b r e : : l p , l ) : : p , a
| (_ , [ ] ) : : p i l e > r a i s e ( Z ip pe r " Deja ␣a d r o i t e " )
| _ > r a i s e ( Z i p p e r " R ac i n e " ) ; ;
|| val a _ dr oi t e : ’ a n a r b r e z i p p e r > ’a narbrezipper = <fu n>
Programmation Fonctionnelle Avancée
Manipulation efficace d’une structure de donnée arborescente
Zippers
Zipper des arbres n-aires
let en_bas : ’ a n a r b r e z i p p e r > ’a narbrezipper =
function ( p i l e , a r b r e ) >match arbre w i t h
| Noeud ( a : : a r b r e s ) > ( [ ] , a r b r e s ) : : p i l e , a
| Noeud _ | F e u i l l e _ > r a i s e ( Z i p p e r " D eja ␣ en ␣ b as " ) ; ;
|| val en_bas : ’ a n a r b r e z i p p e r > ’a narbrezipper = <fu n >
let en_haut : ’ a n a r b r e z i p p e r > a narbrezipper =
function ( p i l e , a r b r e ) >match p i l e w i t h
| ( lp , l ) : : p > p , Noeud ( L i s t . r e v ( l p )@( a r b r e : : l ) )
| _ > r a i s e ( Z i p p e r " D eja ␣ en ␣ h au t " ) ; ;
|| val en_haut : ’ a n a r b r e z i p p e r > a narbrezipper = <f u n>
Programmation Fonctionnelle Avancée
Manipulation efficace d’une structure de donnée arborescente
Zippers
Utilisations
IHuet était motivé par un éditeur structuré de preuves
ILibrairie Clojure http://clojure.org/other_libraries
ILe gestionnaire de fenêtres XMonad (Haskell)
In this picture we have a window manager managing 6 virtual workspaces. Workspace 4 is currently on
screen. Workspaces 1, 2, 4 and 6 are non-empty, and have some windows. The window currently
receiving keyboard focus is window 2 on the workspace 4. The focused windows on the other non-empty
workspaces are being tracked though, so when we view another workspace, we will know which window
to set focus on. Workspaces 3 and 5 are empty.
Programmation Fonctionnelle Avancée
Construction formelle des zippers
Peut-on construire automatiquement des zippers pour un
type quelconque ?
Dériver automatiquement des zippers pour un type quelconque
serait un vrai plus pour un programmeur...
En 2001, Conor McBride observe un phénomène intéressant qui
permet de faire ça en analogie avec la dérivation de fonctions.
Les étapes fondamentales sont les suivantes :
Ion traduit (une sousclasse) des types d’OCaml dans le langage
plus simple des types récursifs
Ion définit formellement la dérivée d’un type récursif
Ion obtient la définition du type du bloc de pile à partir de
cette dérivée
Programmation Fonctionnelle Avancée
Construction formelle des zippers
Les types recursifs polynomiaux
On appelle types récursifs polynomiaux les types produits par la
grammaire suivante, ou xest une variable prise dans un ensemble
denombrable
F::= x|0|1|F+F|F×F|µx.F
Une definition de type en OCaml (ou Haskell, ou SML/NJ, ...) sans
types fonctionnels peut se traduire naturellement dans ces types.
type ’a list = Nil | Cons of ’a * ’a list
devient, en oubliant les noms des constructeurs, et en rendant
explicite la définition récursive
µx.1+’a ×x
Programmation Fonctionnelle Avancée
Construction formelle des zippers
Quelques autres exemples
type ’a tree = Empty | Node of ’a * ’a tree * ’a tree
devient, en oubliant les noms des constructeurs, et en rendant
explicite la définition récursive
µx.1+’a ×x×x
type ’a ntree = Feuille of ’a | Node of ’a ntree list
devient, en oubliant les noms des constructeurs, et en rendant
explicite la définition récursive
µx.’a +x list
c’est à dire
µx.’a + (µy.1+x×y)
1 / 7 100%
La catégorie de ce document est-elle correcte?
Merci pour votre participation!

Faire une suggestion

Avez-vous trouvé des erreurs dans linterface ou les textes ? Ou savez-vous comment améliorer linterface utilisateur de StudyLib ? Nhésitez pas à envoyer vos suggestions. Cest très important pour nous !