10 5 09
play

10/5/09 cs242 Parametric polymorphism Single algorithm may be - PDF document

10/5/09 cs242 Parametric polymorphism Single algorithm may be given many types Type variable may be replaced by any type if f::t t then f::Int Int , f::Bool Bool , ... Overloading A


  1. 10/5/09 ¡ cs242 �  Parametric polymorphism �  Single algorithm may be given many types �  Type variable may be replaced by any type �  if f::t → t then f::Int → Int , f::Bool → Bool , ... �  Overloading �  A single symbol may refer to more than one Kathleen Fisher � algorithm �  Each algorithm may have different type � Reading: “A history of Haskell: Being lazy with class”, �  Choice of algorithm determined by type context � Section 3 ( 3.8), Section 6 (skip 6.4 and 6.7) �  Types of symbol may be arbitrarily different � � “How to Make Ad Hoc Polymorphism less ad hoc”, � � Sections 1 – 7 �  + has types int*int → int , real*real → real , � “Real World Haskell”, Chapter 6: Using Typeclasses � but no others � Thanks to Simon Peyton Jones for some of these slides. Many useful functions are not parametric. � Many useful functions are not parametric. �  Can member work for any type? �  Can serialize work for any type? � member :: [w] -> w -> Bool serialize:: w -> String No! Only for types w for that support equality. � No! Only for types w that support serialization. �  Can sort work for any type? �  Can sumOfSquares work for any type? � sort :: [w] -> [w] sumOfSquares:: [w] -> w No! Only for types w that support ordering. � No! Only for types that support numeric operations. � First Approach � Second Approach �  Allow functions containing overloaded symbols to  Basic operations such as + and * can be overloaded, but not functions defined in terms of them. � define multiple functions: � 3 * 3 -- legal square x = x * x -- legal 3.14 * 3.14 -- legal -- Defines two versions: -- Int -> Int and Float -> Float square x = x * x -- Int -> Int square 3 -- legal  But consider: � square 3.14 -- illegal squares (x,y,z) =  Standard ML uses this approach. � (square x, square y, square z)  Not satisfactory: Why should the language be able to -- There are 8 possible versions! define overloaded operations, but not the programmer? �  This approach has not been widely used because of exponential growth in number of versions. � 1 ¡

  2. 10/5/09 ¡ First Approach � Second Approach �  Equality defined only for types that admit equality : types not containing function or abstract types. �  Make equality fully polymorphic. � 3 * 3 == 9 -- legal (==) :: a -> a -> Bool ‘a’ == ‘b’ -- legal \x->x == \y->y+1 -- illegal  Type of member function: �  Overload equality like arithmetic ops + and * in SML. � member :: [a] -> a -> Bool  But then we can’ t define functions using ‘==‘: �  Miranda used this approach. � member [] y = False  Equality applied to a function yields a runtime error. � member (x:xs) y = (x==y) || member xs y  Equality applied to an abstract type compares the member [1,2,3] 3 -- illegal underlying representation, which violates abstraction member “Haskell” ‘k’ -- illegal principles. �  Approach adopted in first version of SML. � Only provides overloading for ==. � Third Approach �  Make equality polymorphic in a limited way: �  Type classes solve these problems. They � (==) :: a (==) -> a (==) -> Bool  Allow users to define functions using overloaded where a (==) is a type variable ranging only over types operations, eg, square , squares , and member . � that admit equality. �  Generalize ML ’ s eqtypes to arbitrary types. �  Now we can type the member function: �  Provide concise types to describe overloaded member :: [a (==) ] -> a (==) -> Bool functions, so no exponential blow-up. � member [2,3] 4 :: Bool  Allow users to declare new collections of member [‘a’, ‘b’, ‘c’] ‘c’ :: Bool overloaded functions: equality and arithmetic member [\x->x, \x->x + 2] (\y->y *2) -- type error operators are not privileged. �  Approach used in SML today, where the type a (==) is called an “eqtype variable” and is written ``a . �  Fit within type inference framework. �  Consider the “overloaded” function parabola : �  Sorting functions often take a comparison parabola x = (x * x) + x operator as an argument: �  We can rewrite the function to take the overloaded operators as arguments: � qsort:: (a -> a -> Bool) -> [a] -> [a] qsort cmp [] = [] parabola’ (plus, times) x = plus (times x x) x qsort cmp (x:xs) = qsort cmp (filter (cmp x) xs) ++ [x] ++ The extra parameter is a “dictionary” that provides qsort cmp (filter (not.cmp x) xs) implementations for the overloaded ops. � which allows the function to be parametric. �  We have to rewrite our call sites to pass appropriate implementations for plus and times: �  We can use the same idea with other overloaded operations. � y = parabola’(int_plus,int_times) 10 z = parabola’(float_plus, float_times) 3.14 2 ¡

  3. 10/5/09 ¡ Type class Type class instance declarations will declarations generate Dictionary generate instances type and accessor of the Dictionary functions. � data type. � -- Dictionary type -- Dictionary type data MathDict a = MkMathDict (a->a->a) (a->a->a) data MathDict a = MkMathDict (a->a->a) (a->a->a) -- Accessor functions -- Dictionary construction get_plus :: MathDict a -> (a->a->a) intDict = MkMathDict intPlus intTimes get_plus (MkMathDict p t) = p floatDict = MkMathDict floatPlus floatTimes get_times :: MathDict a -> (a->a->a) -- Passing dictionaries get_times (MkMathDict p t) = t y = parabola intDict 10 z = parabola floatDict 3.14 -- “Dictionary-passing style” parabola :: MathDict a -> a -> a If a function has a qualified parabola dict x = let plus = get_plus dict type, the compiler will add a times = get_times dict dictionary parameter and rewrite in plus (times x x) x the body as necessary. � “for all types w that support the Eq operations” �  Type class declarations �  Define a set of operations & give the set a name. � member:: ∀ w. Eq w => w -> [w] -> Bool  The operations == and \= , each with type a -> a -> Bool , form the Eq a type class. �  If a function works for every type with particular properties, the type of the function says just that: �  Type class instance declarations � sort :: Ord a => [a] -> [a]  Specify the implementations for a particular type. � serialise :: Show a => a -> String  For Int, == is defined to be integer equality. � square :: Num n => n -> n squares ::(Num t, Num t1, Num t2) =>  Qualified types � (t, t1, t2) -> (t, t1, t2)  Concisely express the operations required on  Otherwise, it must work for any type whatsoever � otherwise polymorphic type. � reverse :: [a] -> [a] member:: Eq w => w -> [w] -> Bool filter :: (a -> Bool) -> [a] -> [a] FORGET all Works for any type ‘n’ you know that supports the Num about OO operations � classes! � ...the compiler generates this � When you write this... � square :: Num n => n -> n square :: Num n -> n -> n square x = x*x square :: Num n => n -> n The cl class de declaratio ion square d x = (*) d x x square x = x*x says what the Num operations are � class Num a where (+) :: a -> a -> a The “ Num n => ” turns into an extra value e argumen ent (*) :: a -> a -> a to the function. It is a value of data type Num n. negate :: a -> a An in instan ance This extra argument is a di dictio ionary y providing ...etc... de declaratio ion for a implementations of the required operations. � type T says how the instance Num Int where Num operations are a + b = plusInt a b implemented on T’ s � a * b = mulInt a b negate a = negInt a A value of type (Num n) is a dictionary ...etc... plusInt :: Int -> Int -> Int of the Num operations for type n � mulInt :: Int -> Int -> Int etc, defined as primitives 3 ¡

Recommend


More recommend