Last time: monads (etc.) = ⊗ > > 1/ 48
This time: generic programming val show : ’a → string 2/ 48
Generic functions 3/ 48
Data sums unit L () , R 3 () pairs booleans ( f a l s e , 3.0) f a l s e , true records ints { x = { y = ( ) } ; z = true } . . . , − 2 , − 1 ,0 ,1 ,2 , . . . lists floats [ 2 ; 4; 6; 8] , 0.0 , nan , 2.2 e − 308, [ f a l s e ; true ] , [ [ ] ; [ ] ] 3.1416 , i n f i n i t y 4/ 48
Data as trees L ,,, () 10 20 30 40 L () (10 ,20 ,30 ,40) :: , :: 1 ”one” , :: 2 ”two” , [] 3 ”three” [ ( 1 , ”one ” ) ; (2 , ”two ” ) ; (3 , ” t h r e e ” ) ] 5/ 48
Operations defined on (most) data equality ’a → ’a → bool pretty-printing ’a → string hashing ’a → int parsing string → ’a ordering ’a → ’a → int serialising ’a → string mapping (’b → ’b) → ’a → ’a sizing ’a → int querying (’b → bool) → ’a → ’b list 6/ 48
Parameterising by shape 7/ 48
Generic functions and parametricity Some built-in OCaml functions are incompatible with parametricity: v a l (=) : ’ a → ’ a → bool v a l hash : ’ a → i n t v a l f r o m s t r i n g : s t r i n g → i n t → ’ a 8/ 48
Generic functions and parametricity Some built-in OCaml functions are incompatible with parametricity: v a l (=) : ’ a → ’ a → bool v a l hash : ’ a → i n t v a l f r o m s t r i n g : s t r i n g → i n t → ’ a How might we do better? Parameterise by shape : v a l (=) : ’ a data → ’ a → ’ a → bool v a l hash : ’ a data → ’ a → i n t v a l f r o m s t r i n g : ’ a data → s t r i n g → i n t → ’ a 9/ 48
Traversing trees Plan : use shapes to describe how to traverse trees. As we traverse, we’ll apply a function at every node. q a a ⇝ b c d q b q c q d e g h i j q i q e q f q g q h We’ll need a way to traverse data 10/ 48
Traversing trees Plan : use shapes to describe how to traverse trees. As we traverse, we’ll apply a function at every applicable node. a a ⇝ b c d q b q c d e g h i j e q f g q h i We’ll need a way to traverse data We’ll need a way to determine the type of data 10/ 48
Type-indexed values Idea : represent OCaml types by values of some indexed type t: v a l i n t : i n t t v a l bool : bool t v a l ( ∗ ) : ’ a t → ’b t → ( ’ a ∗ ’b) t v a l l i s t : ’ a t → ’ a l i s t t v a l option : ’ a t → ’ a option t ( ∗ etc . ∗ ) Type Representation Representation type int int int t bool bool bool t int ∗ bool int ∗ bool int ∗ bool t int option list list (option int) int option list t 11/ 48
Testing type equality 12/ 48
Type indexed values for type equality type ’ a typeable module Typeable : s i g v a l i n t : i n t typeable v a l bool : bool typeable v a l l i s t : ’ a typeable → ’ a l i s t typeable v a l ( ∗ ) : ’ a typeable → ’b typeable → ( ’ a ∗ ’b) typeable ( ∗ . . . ∗ ) end # Typeable . ( l i s t ( i n t ∗ bool ) ) ; ; − : ( i n t ∗ bool ) l i s t typeable = . . . 13/ 48
Determining type equality at runtime type ( , ) e q l = R e f l : ( ’ a , ’ a ) e q l v a l (=˜=) : ’ a typeable → ’b typeable → ( ’ a , ’ b) e q l option 14/ 48
Representing types type typeable = I n t : i n t typeable | Bool : bool typeable | L i s t : ’ a typeable → ’ a l i s t typeable | Option : ’ a typeable → ’ a option typeable | Pair : ’ a typeable ∗ ’b typeable → ( ’ a ∗ ’b) typeable 15/ 48
Implementing type equality l e t rec eqty : type a b . a typeable → b typeable → (a , b) e q l option = fun l r → match l , r with Int , I n t → Some R e f l | Bool , Bool → Some R e f l | L i s t s , L i s t t → ( match eqty s t with Some R e f l → Some R e f l | None → None ) | Option s , Option t → ( match eqty s t with Some R e f l → Some R e f l | None → None ) | Pair ( s1 , s2 ) , Pair ( t1 , t2 ) → ( match eqty s1 t1 , eqty s2 t2 with Some Refl , Some R e f l → Some R e f l | → None ) | → None 16/ 48
Implementing type equality l e t rec eqty : type a b . a typeable → b typeable → (a , b) e q l option = fun l r → match l , r with Int , I n t → Some R e f l | Bool , Bool → Some R e f l | L i s t s , L i s t t → ( match eqty s t with Some R e f l → Some R e f l | None → None ) | Option s , Option t → ( match eqty s t with Some R e f l → Some R e f l | None → None ) | Pair ( s1 , s2 ) , Pair ( t1 , t2 ) → ( match eqty s1 t1 , eqty s2 t2 with Some Refl , Some R e f l → Some R e f l | → None ) | → None Problem : this representation has no support for user-defined types. 16/ 48
Extensible variants Defining type ’ a t = . . Extending type ’ a t += A : i n t l i s t → i n t t | B : f l o a t l i s t → ’ a t Constructing A [ 1 ; 2 ; 3 ] ( ∗ No d i f f e r e n t to standard v a r i a n t s ∗ ) Matching l e t f : type a . a t → s t r i n g = f u n c t i o n A → ”A” | B → ”B” | → ”unknown” ( ∗ A l l matches must be open ∗ ) 17/ 48
Representing types, extensibly type t y p e r e p = . . type ’ a typeable = { t y p e r e p : ’ a t y p e r e p ; eqty : ’b . ’b t y p e r e p → ( ’ a , ’b) e q l option ; } type t y p e re p += I n t : i n t t y p e r e p l e t e q i n t : type b . b t y p e r e p → ( int , b) e q l option = f u n c t i o n I n t → Some R e f l | → None l e t i n t = { t y p e r e p = I n t ; eqty = e q i n t } 18/ 48
Representing types, extensibly type t y p e r e p = . . type ’ a typeable = { t y p e r e p : ’ a t y p e r e p ; eqty : ’b . ’b t y p e r e p → ( ’ a , ’b) eq option ; } type t y p e re p += L i s t : ’ a t y p e r e p → ’ a l i s t t y p e r e p l e t e q l i s t : type a b . a typeable → b t y p e r e p → ( a l i s t , b) eq option = fun t → f u n c t i o n L i s t a → ( match t . eqty a with Some R e f l → Some R e f l | None → None ) | → None l e t l i s t a = { t y p e r e p = L i s t a . t y p e r e p ; eqty = fun t → e q l i s t a t } 19/ 48
Implementing type equality, extensibly l e t (=˜=) : type a b . a typeable → b typeable → (a , b) e q l option = fun a b → a . eqty b . t y p e r e p 20/ 48
Traversing datatypes 21/ 48
Traversing datatypes gmapT a a ⇝ b c d f b f c f d e g h i j e g h i j gmapQ a [ q b ; q c ; q d ] ⇝ b c d e g h i j 22/ 48
Type indexed values for traversable types type ’ a data module Data : s i g v a l i n t : i n t data v a l bool : bool data v a l l i s t : ’ a data → ’ a l i s t data v a l ( ∗ ) : ’ a data → ’b data → ( ’ a ∗ ’b) data ( ∗ . . . ∗ ) end # Data . ( l i s t ( i n t ∗ bool ) ) ; ; − : ( i n t ∗ bool ) l i s t data = . . . 23/ 48
Polymorphic types for generic traversals: gmapT a a ⇝ b c d f b f c f d e g h i j e g h i j v a l gmapT : ’ a data → ( ∀ ’b . ’ b data → ’b → ’b) → ’ a → ’ a 24/ 48
Polymorphic types for generic traversals: gmapT a a ⇝ b c d f b f c f d e g h i j e g h i j type gmapT arg = { f : ’b . ’b data → ’b → ’b ; } v a l gmapT : ’ a data → gmapT arg → ’ a → ’ a 25/ 48
Polymorphic types for generic queries: gmapQ a [q b; q c; q d] ⇝ b c d e g h i j v a l gmapQ : ’ a data → ( ∀ ’b . ’ b data → ’b → ’u) → ’ a → ’u l i s t 26/ 48
Polymorphic types for generic queries: gmapQ a [q b; q c; q d] ⇝ b c d e g h i j type ’u gmapQ arg = { q : ’ b . ’b term → ’b → ’u } v a l gmapQ : ’ a data → ’u gmapQ arg → ’ a → ’u l i s t 27/ 48
Traversing datatypes: primitive types x x ⇝ gmapT int f l e t gmapT int f x = x l e t gmapQ int q x = [ ] 28/ 48
Traversing datatypes: pairs , , ⇝ x y f x f y gmapT (a ∗ b) f l e t gmapT pair { f } ( x , y ) = ( f a x , f b y ) l e t gmapQ pair { q } ( x , y ) = [ q a x ; q b y ] 29/ 48
Traversing datatypes: lists :: :: w :: f w f :: x :: x :: ⇝ y :: y :: z [] z [] let l = list a in gmapT l f l e t gmapT list { f } = f u n c t i o n [ ] → [ ] | x : : xs → f a x : : f l xs l e t gmapQ list { q } = f u n c t i o n [ ] → [ ] | x : : xs → [ q a x ; q l xs ] 30/ 48
Type indexed values for traversals type ’ a data = { typeable : ’ a typeable ; gmapT : gmapT arg → ’ a → ’ a ; gmapQ : ’u . ’u gmapQ arg → ’ a → ’u l i s t ; } and gmapT arg = { f : ’b . ’b data → ’b → ’b ; } and ’u gmapQ arg = { q : ’ b . ’b data → ’b → ’u } 31/ 48
Recommend
More recommend