Presentation is loading. Please wait.

Presentation is loading. Please wait.

Generic Programming ___________ III Rinus Plasmeijer University of Nijmegenclean.cs.ru.nl/

Similar presentations


Presentation on theme: "Generic Programming ___________ III Rinus Plasmeijer University of Nijmegenclean.cs.ru.nl/"— Presentation transcript:

1 Generic Programming ___________ III Rinus Plasmeijer University of Nijmegenclean.cs.ru.nl/

2 2 Generic programming I:Mimic generic programming using the overloading mechanism - more work than writing functions by hand: additional definitions have to made - but in this way we understand how it works II:Support for Generic Programming as offered by Clean - less work than writing functions by hand the compiler will generate definitions for us III: iTask: Application using a lot of generic programming techniques

3 3 A class for each kind … class map0 t :: t  t// t :: * class map1 t ::(a  b) (t a)  (t b)// t :: *  * class map2 t ::(a  b) (c  d) (t a c)  (t b d) // t :: *  *  * One general approach: the “a class for each kind” is also used for our simple kind * examples... class eq0 t :: t t  Bool// t :: * class eq1 t :: (a a  Bool) (t a) (t a)  Bool// t :: *  * class eq2 t :: (a a  Bool) (b b  Bool) (t a b) (t a b)  Bool// t :: *  *  *

4 4 T1T1 The generic scheme T2T2 Generic GT 1 Generic GT 2 fun :: T 1  T 2 fromT 1 toT 2 gfun :: GT 1  GT 2

5 5 Applying the kind-indexed generic scheme by hand (I). What do we have to define for a generic function, eg. for map: 1. For every type of a specific kind, a class has to be defined: class map0 t :: t  t class map1 t ::(a  b) (t a)  (t b) class map2 t ::(a  b) (c  d) (t a c)  (t b d) class mapi t :: … 2. For every type applied, conversion functions to and from the generic domain are needed: :: List a = Nil | Cons a (List a) :: ListG a :== EITHER (CON UNIT) (CON (PAIR a (List a))) fromList :: (List a)  ListG a toList :: (ListG a)  List a

6 6 Applying the kind-indexed generic scheme by hand (II). 3. Instantiate the generic classes for the basic types used and all generic types instance map0 Intwhere map0 i = I instance map0 UNITwheremap0 UNIT = UNIT instance map2 PAIRwhere map2 f g (PAIR x y) = PAIR (f x) (g y) instance map2 EITHERwheremap2 f g (LEFT x) = LEFT (f x) map2 f g (RIGHT y) = RIGHT (g y) instance map1 CONwhere map1 f (CON n x) = CON n (f x) 4. Instantiate the generic class for the types you want to apply the generic function on… instance map1 Listwheremap1 f list = (toList o (map2 (map1 map0) (map1 (map2 f (map1 f)))) o fromList ) list

7 7 Generic programming I:Mimic generic programming using the overloading mechanism - more work than writing functions by hand: additional definitions have to made - but in this way we understand how it works II:Support for Generic Programming as offered by Clean - less work than writing functions by hand the compiler will generate definitions for us III: iTask: Application using a lot of generic programming techniques

8 8 Using the generic mechanism in Clean You only have to define: 3. The generic function for I:the generic domain and II:all basic types (Int, Real, …) and non-algebraic types (arrays) it is applied on… The compiler will automatically: 1. Create a class for every kind being used. 2. Generate conversion functions to and from the generic domain: 4. Generate an instance of the generic function for your type But, you have to ask for it ! This is not needed, but done for pragmatically reasons. A lot of code is generated …

9 9 T1T1 The generic scheme T2T2 Generic T 1 Generic T 2 fun :: T 1  T 2 fromT 1 toT 2 gfun :: T 1  T 2

10 10 StdGeneric: Support types for generic programming definition module StdGeneric … // generic representation :: UNIT = UNIT :: EITHER a b = LEFT a | RIGHT b :: PAIR a b = PAIR a b // information about types and constructors being used :: CONS a= CONS a // constructor information :: OBJECT a = OBJECT a// type information :: FIELD a = FIELD a // record field information

11 11 Defining generic equality in Clean (1) - The signature of a generic function has to be defined in a special class. - The type scheme is the type of the generic function for kind * generic gEq a :: a a  Bool

12 12 Defining generic equality in Clean (2) -Define instances for the generic types UNIT, PAIR, and EITHER: import StdGeneric gEq {|UNIT|} UNIT UNIT = True gEq {|PAIR|} eqx eqy (PAIR x1 y1) (PAIR x2 y2) = eqx x1 x2 && eqy y1 y2 gEq {|EITHER|} eql eqr (LEFT x) (LEFT y) = eql x y gEq {|EITHER|} eql eqr (RIGHT x) (RIGHT y) = eqr x y gEq {|EITHER|} eql eqr _ _ = False -Between {| |} the type for which the generic function is defined is specified. -The number of additional arguments depends on the kind of the type. -The compiler knows the kind of a type and can deduce the type class for it, given the type for kind *: generic gEq a :: a a  Bool gEq {|*  *|} :: (a a  Bool) (t a) (t a)  Bool gEq {|*  *  *|} :: (a a  Bool) (b b  Bool) (t a b) (t a b)  Bool

13 13 Defining generic equality in Clean For convenience there are two additional generic types: :: CONS a= CONS a Gives information on the constructor being used. :: OBJECT a = OBJECT a Gives information about the type as it is defined in the application. Hence, :: List a = Nil | Cons a (List a) Has the following generic representation: :: ListG a :== OBJECT (EITHER (CONS UNIT) (CONS (PAIR a (List a))))

14 14 Defining generic equality in Clean (3) One has to define instances for CONS and OBJECT, even if the information is not used. for CONStructors (Mandatory): gEq{|CONS|} eq (CONS x) (CONS y) = eq x y for Types (Mandatory): gEq{|OBJECT|} eq (OBJECT x) (OBJECT y) = eq x y

15 15 Defining generic equality in Clean (4) Records are a special kind of data structure. If you are using records, one has to instantiate the generic FIELD type. Similar to CONS and OBJECT, it can be used to obtain type information, In this case information about the record fields... If gEq is applied to a record, one has to define: gEq{|FIELD|} eq (FIELD x) (FIELD y) = eq x y

16 16 Defining generic equality in Clean (5) Instances have to be defined for any predefined type, but only if gEq is applied on them: for basic types, Int, Real, Bool, String: gEq{|Int|} x y = x == y// == on Int is used gEq{|Real|} x y = x == y// == on Real is used for arrays, {}, {!}, {#}: gEq{|{}|} eq xs ys = size xs == size ys && and [eq x y \\ x <-: xs & y <-: ys] gEq{|{!}|} eq xs ys = size xs == size ys && and [eq x y \\ x <-: xs & y <-: ys]

17 17 All definitions once again… generic gEq a :: a a  Bool Mandatory for the generic types: gEq {|UNIT|} UNIT UNIT = True gEq {|PAIR|} eqx eqy (PAIR x1 y1) (PAIR x2 y2) = eqx x1 x2 && eqy y1 y2 gEq {|EITHER|} eql eqr (LEFT x) (LEFT y) = eql x y gEq {|EITHER|} eql eqr (RIGHT x) (RIGHT y) = eqr x y gEq {|EITHER|} eql eqr _ _ = False gEq{|CONS|} eq (CONS x) (CONS y) = eq x y gEq{|OBJECT|} eq (OBJECT x) (OBJECT y) = eq x y Also define qEq for predefined types one wants to apply it on: gEq{|Int|} x y = x == y// Int gEq{|Real|} x y = x == y// Real gEq{|FIELD|} eq (FIELD x) (FIELD y) = eq x y// Records gEq{|{}|} eq xs ys =...// Array

18 18 Deriving generic functions for user defined types For all (first order) user types T generic functions can be derived automatically on demand ! derive gEq T This has to be done for all types one wants to apply the generic function on. derive gEq T 1, T 2, …, T n Note: -Generic function instantiations and derives can be spread across modules -A derive can be specified in any module where needed, also for types defined elsewhere -Generic functions derived can be exported (in dcl):derive gEq T // if defined or derived in corresponding.icl and imported:import gEq// imports all exported instances -The system cannot derive a generic function for abstract types. But one can derive a generic function in the corresponding.icl module and export it in the.dcl module. -The system cannot derive a generic function for function types.

19 19 Applying generic equality (1) :: Tree a b = Tip a | Bin b (Tree a b) (Tree a b) derive gEq Tree myFun = gEq (Bin 1 (Tip “a”) (Tip “b”)) (Bin 1 (Tip “a”) (Tip “c”)) Error: gEq generic: missing kind argument ! Remember: there are many classes, for every kind there is one… One can use any of them, but one has to indicate which one to use…

20 20 Applying generic equality (1) :: Tree a b = Tip a | Bin b (Tree a b) (Tree a b) derive gEq Tree myFun = gEq {|*|} (Bin 1 (Tip “a”) (Tip “b”)) (Bin 1 (Tip “a”) (Tip “c”))

21 21 Applying generic equality (2) :: Tree a b = Tip a | Bin b (Tree a b) (Tree a b) derive gEq Tree myEq :: (Tree a b) (Tree a b)  Bool | gEq {|*|} a & gEq {|*|} b myEq t1 t2 = gEq {|*|} t1 t2 A function can become overloaded when using generic functions. In that case the dependency is indicated in context restriction of its type, as usual.

22 22 Applying generic equality (3) :: Tree a b = Tip a | Bin b (Tree a b) (Tree a b) derive gEq Tree myEq` :: (a a  Bool) (b b  Bool) (Tree a b) (Tree a b)  Bool myEq` myeqa myeqb t1 t2 = gEq {|*  *  *|} myeqa myeqb t1 t2 This function will walk through the two trees using the generic scheme, But it uses ad-hoc functions to compare the elements of type a and b... In this way one can mix the generic behaviour with customized behaviour..

23 23 Applying generic equality (4) :: Tree a b = Tip a | Bin b (Tree a b) (Tree a b) derive gEq Tree myEq`` :: (b b  Bool) (Tree a b) (Tree a b)  Bool | gEq {|*|} a myEq`` myeqb t1 t2 = gEq {|*  *  *|} gEq {|*|} myeqb t1 t2 This function will walk through the two trees using the generic scheme, For comparing elements of type a the generic scheme is used, for comparing type b an ad-hoc user-defined function is used...

24 24 Specialization When defining a generic function: 1: Define instances for the generic types 2: Define instances for the basic types (because they are special) 3: Derive instances for the user-defined types This give a general algorithm which works for any type. Generic programming = 1. defining a general rule 2. defining exceptions to this rule :: MyType a b = … gEq{|MyType|} eqa eqb mytype1 mytype2 = …

25 25 Obtaining information about the constructor used (1) // and if you want to use the information: gFun {|CONS of c|} gfun (CONS x) (CONS y) =... c... c is a record defined in StdGeneric of type GenericConsDescriptor gFun {|OBJECTof t|} gfun (OBJECT x) (OBJECT y) =... t... t is a record defined in StdGeneric of type GenericTypeDefDescriptor gFun {|FIELD of f|} gfun (FIELD x) (FIELD y) =... f... f is a record defined in StdGeneric of type GenericFieldDescriptor The descriptors are different, giving access to the most important information (which cons, which type, which field do we have here), but all descriptors refer to each other. All information about the type is available at each descriptor.

26 26 Obtaining information about the constructor used (2) :: GenericConsDescriptor = { gcd_name :: String // name of constructor, gcd_arity :: Int // arity of constructor, gcd_prio :: GenConsPrio // priority and associativity, gcd_type_def:: GenericTypeDefDescriptor // type def of constructor, gcd_type :: GenType // type of the constructor, gcd_fields :: [GenericFieldDescriptor] // non-empty for records, gcd_index :: Int // index in the type def } :: GenConsPrio = GenConsNoPrio | GenConsPrio GenConsAssoc Int :: GenConsAssoc = GenConsAssocNone | GenConsAssocLeft | GenConsAssocRight :: GenType = GenTypeCons String | GenTypeVar Int | GenTypeApp GenType GenType | GenTypeArrow GenType GenType This give a complete description of the type as defined by the user. It reveals the type definition (e.g. Tree a b), but NOT the concrete type (e.g. Tree Int Real).

27 27 Obtaining information about the constructor used (2) :: GenericTypeDefDescriptor ={ gtd_name :: String, gtd_arity :: Int, gtd_num_conses :: Int, gtd_conses :: [GenericConsDescriptor] } :: GenericFieldDescriptor = { gfd_name :: String, gfd_index :: Int, gfd_cons :: GenericConsDescriptor } Field descriptors are used for record definitions. They are an extension of the CONS information: name + position of the field.

28 28 generic map defined in Clean generic gMap a b ::.a ->.b gMap{|Int|} x = x gMap{|Real|} x = x gMap{|UNIT|} x = x gMap{|PAIR|} mapx mapy (PAIR x y) = PAIR (mapx x) (mapy y) gMap{|EITHER|} mapl mapr (LEFT x) = LEFT (mapl x) gMap{|EITHER|} mapl mapr (RIGHT x) = RIGHT (mapr x) gMap{|CONS|} map (CONS x) = CONS (map x) gMap{|FIELD|} map (FIELD x) = FIELD (map x) gMap{|OBJECT|} map (OBJECT x) = OBJECT (map x)

29 29 generic map defined in Clean generic gMap a b ::.a ->.b gMap{|c|} x = x// shorthand for all kind * gMap{|PAIR|} mapx mapy (PAIR x y) = PAIR (mapx x) (mapy y) gMap{|EITHER|} mapl mapr (LEFT x) = LEFT (mapl x) gMap{|EITHER|} mapl mapr (RIGHT x) = RIGHT (mapr x) gMap{|CONS|} map (CONS x) = CONS (map x) gMap{|FIELD|} map (FIELD x) = FIELD (map x) gMap{|OBJECT|} map (OBJECT x) = OBJECT (map x)

30 30 using this gMap :: Tree a = Tip | Node a (Tree a) (Tree a) myTree = Node 5 (Node 3 (Node 2 (Node 1 Tip Tip) Tip) Tip) (Node 6 Tip (Node 7 Tip Tip)) derive gMap [], Tree, (,) example1 = gMap{|*->*|} fib [1..42] example2 = gMap{|*->*|} fib myTree example3= gMap{|*->*->*|} fib not (10, True)


Download ppt "Generic Programming ___________ III Rinus Plasmeijer University of Nijmegenclean.cs.ru.nl/"

Similar presentations


Ads by Google