generic programming ___________ iii rinus plasmeijer university of nijmegenclean.cs.ru.nl

30
Generic Programming ___________ III Rinus Plasmeijer University of Nijmegen clean.cs.ru.nl/

Upload: adela-butler

Post on 04-Jan-2016

214 views

Category:

Documents


1 download

TRANSCRIPT

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

Generic Programming___________

III

Rinus Plasmeijer

University of Nijmegen clean.cs.ru.nl/

Page 2: Generic Programming ___________ III Rinus Plasmeijer University of Nijmegenclean.cs.ru.nl

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 handthe compiler will generate definitions for us

III: iTask: Application using a lot of generic programming techniques

Page 3: Generic Programming ___________ III Rinus Plasmeijer University of Nijmegenclean.cs.ru.nl

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 :: * * *

Page 4: Generic Programming ___________ III Rinus Plasmeijer University of Nijmegenclean.cs.ru.nl

4

T1

The generic scheme

T2

Generic GT1 Generic GT2

fun :: T1 T2

fromT1 toT2

gfun :: GT1 GT2

Page 5: Generic Programming ___________ III Rinus Plasmeijer University of Nijmegenclean.cs.ru.nl

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 tclass 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 atoList :: (ListG a) List a

Page 6: Generic Programming ___________ III Rinus Plasmeijer University of Nijmegenclean.cs.ru.nl

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 Int where map0 i = Iinstance map0 UNIT where map0 UNIT = UNITinstance map2 PAIR where map2 f g (PAIR x y) = PAIR (f x) (g y)instance map2 EITHER where map2 f g (LEFT x) = LEFT (f x)

map2 f g (RIGHT y) = RIGHT (g y)instance map1 CON where 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 List where map1 f list = (toList o

(map2 (map1 map0) (map1 (map2 f (map1 f)))) o

fromList ) list

Page 7: Generic Programming ___________ III Rinus Plasmeijer University of Nijmegenclean.cs.ru.nl

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 handthe compiler will generate definitions for us

III: iTask: Application using a lot of generic programming techniques

Page 8: Generic Programming ___________ III Rinus Plasmeijer University of Nijmegenclean.cs.ru.nl

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 …

Page 9: Generic Programming ___________ III Rinus Plasmeijer University of Nijmegenclean.cs.ru.nl

9

T1

The generic scheme

T2

Generic T1 Generic T2

fun :: T1 T2

fromT1 toT2

gfun :: T1 T2

Page 10: Generic Programming ___________ III Rinus Plasmeijer University of Nijmegenclean.cs.ru.nl

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

 

Page 11: Generic Programming ___________ III Rinus Plasmeijer University of Nijmegenclean.cs.ru.nl

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

 

Page 12: Generic Programming ___________ III Rinus Plasmeijer University of Nijmegenclean.cs.ru.nl

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 ygEq {|EITHER|} eql eqr (RIGHT x) (RIGHT y) = eqr x ygEq {|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) BoolgEq {|** *|} :: (a a Bool) (b b Bool) (t a b) (t a b) Bool

 

Page 13: Generic Programming ___________ III Rinus Plasmeijer University of Nijmegenclean.cs.ru.nl

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))))

 

Page 14: Generic Programming ___________ III Rinus Plasmeijer University of Nijmegenclean.cs.ru.nl

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

 

Page 15: Generic Programming ___________ III Rinus Plasmeijer University of Nijmegenclean.cs.ru.nl

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

 

Page 16: Generic Programming ___________ III Rinus Plasmeijer University of Nijmegenclean.cs.ru.nl

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 usedgEq{|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]

Page 17: Generic Programming ___________ III Rinus Plasmeijer University of Nijmegenclean.cs.ru.nl

17

All definitions once again…

generic gEq a :: a a Bool

Mandatory for the generic types:gEq {|UNIT|} UNIT UNIT = TruegEq {|PAIR|} eqx eqy (PAIR x1 y1) (PAIR x2 y2) = eqx x1 x2 && eqy y1 y2gEq {|EITHER|} eql eqr (LEFT x) (LEFT y) = eql x ygEq {|EITHER|} eql eqr (RIGHT x) (RIGHT y) = eqr x ygEq {|EITHER|} eql eqr _ _ = FalsegEq{|CONS|} eq (CONS x) (CONS y) = eq x ygEq{|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 // IntgEq{|Real|} x y = x == y // Real

gEq{|FIELD|} eq (FIELD x) (FIELD y) = eq x y // Records

gEq{|{}|} eq xs ys = ... // Array

Page 18: Generic Programming ___________ III Rinus Plasmeijer University of Nijmegenclean.cs.ru.nl

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 T1, T2, … , Tn

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 .icland 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 moduleand export it in the .dcl module.

- The system cannot derive a generic function for function types.

Page 19: Generic Programming ___________ III Rinus Plasmeijer University of Nijmegenclean.cs.ru.nl

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…

Page 20: Generic Programming ___________ III Rinus Plasmeijer University of Nijmegenclean.cs.ru.nl

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”))

Page 21: Generic Programming ___________ III Rinus Plasmeijer University of Nijmegenclean.cs.ru.nl

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.

Page 22: Generic Programming ___________ III Rinus Plasmeijer University of Nijmegenclean.cs.ru.nl

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..

Page 23: Generic Programming ___________ III Rinus Plasmeijer University of Nijmegenclean.cs.ru.nl

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 {|*|} amyEq`` 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...

Page 24: Generic Programming ___________ III Rinus Plasmeijer University of Nijmegenclean.cs.ru.nl

24

Specialization

When defining a generic function:

1: Define instances for the generic types2: 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 rule2. defining exceptions to this rule

:: MyType a b = …

gEq{|MyType|} eqa eqb mytype1 mytype2 = …

Page 25: Generic Programming ___________ III Rinus Plasmeijer University of Nijmegenclean.cs.ru.nl

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.

Page 26: Generic Programming ___________ III Rinus Plasmeijer University of Nijmegenclean.cs.ru.nl

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).

Page 27: Generic Programming ___________ III Rinus Plasmeijer University of Nijmegenclean.cs.ru.nl

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.

Page 28: Generic Programming ___________ III Rinus Plasmeijer University of Nijmegenclean.cs.ru.nl

28

generic map defined in Clean

generic gMap a b :: .a -> .b

gMap{|Int|} x = xgMap{|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)

Page 29: Generic Programming ___________ III Rinus Plasmeijer University of Nijmegenclean.cs.ru.nl

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)

Page 30: Generic Programming ___________ III Rinus Plasmeijer University of Nijmegenclean.cs.ru.nl

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)