Priciples of programmig laguages From last week Lecture 5 http://few.vu.l/~silvis/ppl/2007 Natalia Silvis-Cividjia e-mail: silvis@few.vu.l ML has o assigmet. Explai how to access a old bidig? Is & for logical ad? If both operads are boolea, the & ca be used as && but without short-circuitig ML: Value of a i halve? vrije Uiversiteit amsterdam Outlie Part I. Polymorphism Part II. Fuctioal programmig. Third look at ML. 1
What is polymorphism? Polymorphism poly+morphos (Greek) = may forms (shapes) Used i may other scieces: material sciece, biology I programmig laguages PMF is difficult to defie: Applies to a wide variety of laguage features Most laguages have at least a little First we examie a few major examples, the we try to give a defiitio that covers them Polymorfism examples Overloadig Parameter coercio Parametric polymorphism Defiitios ad classificatios What is overloadig? Overloadig = to give more tha oe defiitio, all of differet types You ca overload: operators or fuctio ames Predefied Overloaded Operators Some operators are already overloaded by the laguage itself. ML: val x = 1 + 2; val y = 1.0 + 2.0; C++: a = 1 + 2; b = 1.0 + 2.0; c = "hello " + "there"; How does the laguages system kow which defiitio to use? 2
User-Overloaded Operators Situatios: You ca add two itegers or two floats, but what if you wat to add two complex umbers? You ca compare two itegers, two strigs, but how to compare 2 C structures? Ex: Overloadig the < operator i C++ #iclude <iostream> #iclude <strig> usig amespace std ; struct Studet { strig ame ; it stud_r ; it grade ; ; // overloads < operator to compare 2 structs of type Studet bool operator< (cost Studet& studet1, cost Studet& studet2) { if (studet1.grade < studet2.grade) retur true ; else retur false ; Ex: Overloadig the < operator i C++ (ctd) it mai() { Studet me, you ; me.ame = "Sheila" ; me.stud_r =14537780 ; me.grade = 8 ; you.ame = "Bob" ; you.stud_r =14532180 ; you.grade = 4 ; if (me < you) cout << you.ame << " is more clever tha " << me.ame ; else cout << me.ame << " is more clever tha " << you.ame ; cout << edl ; retur 0 ; Output: Sheila is more cleaver tha Bob C++ Operator overloadig rules All operators ca be overloaded except:. (direct member), :: (scope resolutio),.* ad?: You caot chage the uary/biary ature of a operator. You caot override precedece rules. Take care! Overloadig ca become cofusig. The user has to use his commo sese ad ot overdo it. Overloaded Fuctio Names I some laguages (Java, C++), the user ca overload the fuctio ame = same ame, differet defiitio (differet sematics) it square(it x) { retur x*x; double square(double x) { retur x*x; The bodies look the same, but the implemetatio by hardware is very differet. Implemetig Overloadig Compilers implemet overloadig (solve the ambiguity) like this: Create a set of moomorphic fuctios, oe for each defiitio Ivet a magled ame for each, ecodig the type iformatio Ex: fred_fii Have each referece use the appropriate magled ame, depedig o the parameter types 3
Mai feature of overloadig Polymorphism examples The laguage system looks at the operators type ad decides which defiitio to use. Overloadig Parameter coercio Parametric polymorphism Defiitios ad classificatios Coercio Defiig Coercios A coercio is a implicit type coversio, supplied automatically Explicit type coversio i Java: Implicit coversio (Coercio) i Java: OR double x; x = (double) 2; double x; x = 2; This coercio is ot polymorphism, x is ot polymorphic Laguage defiitios ofte take may pages to defie exactly which coercios are performed Some laguages, especially some older laguages like Algol 68 ad PL/I, have very extesive powers of coercio Some, like ML, have oe Most, like Java, are somewhere i the middle Defiig coercio i Java 5.6.1 Uary Numeric Promotio Some operators apply uary umeric promotio to a sigle operad, which must produce a value of a umeric type: If the operad is of compile-time type byte, short, or char, uary umeric promotio promotes it to a value of type it by a wideig coversio ( 5.1.2). Otherwise, a uary umeric operad remais as is ad is ot coverted. Uary umeric promotio is performed o expressios i the followig situatios: the dimesio expressio i array creatios ( 15.9); the idex expressio i array access expressios ( 15.12); operads of the uary operators plus + ( 15.14.3) ad mius - ( 15.14.4)... Parameter Coercio if a laguage supports coercio of parameters o a fuctio call (or of operads whe a operator is applied), the resultig fuctio (or operator) is polymorphic The Java Laguage Specificatio James Goslig, Bill Joy, Guy Steele 4
Example: Java void f(double x) { f((byte) 1); f((short) 2); f('a'); f(3); f(4l); f(5.6f); This f ca be called with ay type of parameter Java is willig to coerce to type double f is polymorphic Coercio vs. Overloadig There are potetially tricky iteractios betwee overloadig ad coercio Overloadig uses the types to choose the defiitio Coercio uses the defiitio to choose a type coversio Ambiguities might appear ad each laguage system has to solve them i some way. Ambiguity Example Ambiguity Example Suppose that, like C++, a laguage is willig to coerce char to it or to double it square(it x) { retur x*x; double square(double x) { retur x*x; Which square gets called for square('a')? Suppose that, like C++, a laguage is willig to coerce char to it Which f gets called for f('a', 'b')? void f(it x, char y) { void f(char x, it y) { Outlie Parametric Polymorphism Overloadig Parameter coercio Parametric polymorphism Defiitios ad classificatios A fuctio exhibits parametric polymorphism if it has a type that cotais oe or more type variables - fu f(a, b) = (a = b); val f = f : ''a * ''a -> bool A type with type variables is a polytype Foud i ML, C++ ad Ada, Java 5
Ex: C++ Fuctio templates // returs the maximum of 2 itegers it max (it left, it right) { if (left < right) retur right ; else retur left ; What is the problem here? What do we eed to solve it? //returs the maximum of 2 doubles double max (double left, double right) { if (left < right) retur right ; else retur left ; Ex: C++ Fuctio templates A fuctio template for the fuctio max: template <class T> T max (T left, T right) { if (left < right) retur right ; else retur left ; Here class T meas type T. T is a type variable T ca be ay type for which the operator < is defied For other types, operator < ca be overloaded. Ex: C++ Fuctio templates #iclude <iostream> usig amespace std;.. place here the fuctio template it mai() { it iteger1 = 4 ; it iteger2 = 10 ; it max1 = max (iteger1, iteger2); cout << "The maximum iteger is " << max1 << edl ; double double1 = 100.20 ; double double2 = 5.7 ; double max2 = max (double1,double2) ; cout << "The maximum double is " << max2 << edl ; retur 0 ; Implemetatio May copies vs. oe copy A improved implemetatio for parametric polymorphism is a active are of programmig laguage research Outlie Overloadig Parameter coercio Parametric polymorphism Defiitios ad classificatios So what is polymorphism? 6
A attempt at a defiitio A fuctio or operator is polymorphic if it has at least two possible types. How may types? ad hoc polymorphism if it has oly fiitely may possible types uiversal polymorphism if it has ifiitely may possible types Ad hoc/uiversal? Summary Overloadig Parametric coercio Parametric polymorphism Ad hoc Ad hoc Uiversal Coclusio There are may more pheomea that people call polymorphism. We preseted oly 3 examples ad gave a defiitio that covers them. Laguages with dyamic type checkig do ot eed polymorphism. Polymorphism is a way to gai some freedom ad flexibility ad still beefit from the static type checkig Polymorphism is powerful ad flexible feature but it presets opportuities for abuse. Exercises 1.(Weber Ch.8 ex.1) try yourself at home 2.(Weber Ch.8 ex.3) (i class) Cosider a ukow laguage with iteger ad real types i which 1+2, 1.0+2, 1+2.0 ad 1.0 + 2.0 are all legal expressios. a. Explai how this could be the result of coercio, usig o overloadig b. Explai how this could be the result of overloadig usig o coercio c. Explai how this could result from a combiatio of overloadig ad coercio 7
Outlie Outlie Part II. Fuctioal programmig. A third look at ML More patter matchig Fuctio values ad aoymous fuctios Higher-order fuctios ad curryig Some ML predefied higher-order fuctios More Patter-Matchig Match Sytax Last time we saw patter-matchig i fuctio defiitios: A rule: <rule> ::= <patter> => <expressio> fu f 0 = "zero" f _ = "o-zero"; A match cosists of oe or more rules separated by a vertical bar, like this: <match> ::= <rule> <rule> ' ' <match> Case Expressios Example - case 1+1 of = 3 => "three" = 2 => "two" = _ => "hmm"; val it = "two" : strig case x of _::_::c::_ => c _::b::_ => b a::_ => a il => 0 8
Geeralizes if if exp 1 the exp 2 else exp 3 case exp 1 of true => exp 2 false => exp 3 Behid the Scees Expressios usig if are actually treated as abbreviatios for case expressios This explais some odd SML/NJ error messages: The two expressios above are equivalet So if-the-else is really just a special case of case - if 1=1 the 1 else 1.0; Error: types of rules do't agree [literal] earlier rule(s): bool -> it this rule: bool -> real i rule: false => 1.0 Outlie Predefied Fuctios More patter matchig Fuctio values ad aoymous fuctios Higher-order fuctios ad curryig Predefied higher-order fuctios Whe a ML laguage system starts, there are may predefied variables Some are boud to fuctios: - ord; val it = f : char -> it - ~; val it = f : it -> it Defiig Fuctios Fuctio Values We have see the fu otatio for defiig ew amed fuctios You ca also defie ew ames for old fuctios, usig val just as for other kids of values: - val x = ~; val x = f : it -> it - x 3; val it = ~3 : it Fuctios i ML do ot have ames Just like other kids of values, fuctio values may be give oe or more ames by bidig them to variables The fu sytax does two separate thigs: Creates a ew fuctio value Bids that fuctio value to a ame 9
Aoymous Fuctios Named fuctio: fu - fu f x = x + 2; val f = f : it -> it - f 1; val it = 3 : it Aoymous fuctio: f - f x => x + 2; val it = f : it -> it - (f x => x + 2) 1; val it = 3 : it Usig Aoymous Fuctios whe you eed a small fuctio i just oe place ad you wat to avoid clutterig With amed fuctio - fu itbefore (a,b) = a < b; val itbefore = f : it * it -> bool - quicksort ([1,4,3,2,5], itbefore); val it = [1,2,3,4,5] : it list With aoymous fuctio: - quicksort ([1,4,3,2,5], f (a,b) => a<b); val it = [1,2,3,4,5] : it list - quicksort ([1,4,3,2,5], f (a,b) => a>b); val it = [5,4,3,2,1] : it list The op keyword - op *; val it = f : it * it -> it - quicksort ([1,4,3,2,5], op <); val it = [1,2,3,4,5] : it list Biary operators are special fuctios The keyword op before a operator extracts the fuctio used by the operator Outlie Higher-order Fuctios More patter matchig Fuctio values ad aoymous fuctios Higher-order fuctios ad curryig Predefied higher-order fuctios Every fuctio has a order: A fuctio that does ot take ay fuctios as parameters, ad does ot retur a fuctio value, has order 1 A fuctio that takes a fuctio as a parameter or returs a fuctio value has order +1, where is the order of its highest-order parameter or retured value The quicksort we just saw is a secodorder fuctio 10
Practice What is the order of fuctios with each of the followig ML types? it * it -> bool it list * (it * it -> bool) -> it list it -> it -> it (it -> it) * (it -> it) -> (it -> it) it -> bool -> real -> strig Curryig I ML fuctios have oly oe parameter. Q: How to pass 2 parameters to a fuctio? A1: By passig a 2-tuple: fu f (a,b) = a + b; A2: By curryig = write a fuctio that takes the first argumet, ad returs aother fuctio that takes the secod argumet ad returs the fial result: fu g a = f b => a+b; Haskell B. Curry, (1900-1982) FP mathematicia Example - fu f (a,b) = a+b; val f = f : it * it -> it - fu g a = f b => a+b; val g = f : it -> it -> it - f(2,3); val it = 5 : it - g 2 3; val it = 5 : it Remember that fuctio applicatio is leftassociative So g 2 3 meas ((g 2) 3) 11
Advatages No tuples: we write g 2 3 istead of f(2,3) But the real advatage: we get to specialize fuctios for particular iitial parameters - val add2 = g 2; val add2 = f : it -> it - add2 3; val it = 5 : it - add2 10; val it = 12 : it Advatages - quicksort (op <) [1,4,3,2,5]; val it = [1,2,3,4,5] : it list - val sortbackward = quicksort (op >); val sortbackward = f : it list -> it list - sortbackward [1,4,3,2,5]; val it = [5,4,3,2,1] : it list Multiple Curried Parameters Curryig geeralizes to ay umber of parameters - fu f (a,b,c) = a+b+c; val f = f : it * it * it -> it - fu g a = f b => f c => a+b+c; val g = f : it -> it -> it -> it - f (1,2,3); val it = 6 : it - g 1 2 3; val it = 6 : it Easier Notatio for Curryig Istead of writig: fu f a = f b => a+b; We ca just write: fu f a b = a+b; This geeralizes for ay umber of curried argumets - fu f a b c d = a+b+c+d; val f = f : it -> it -> it -> it -> it Outlie ML Predefied Higher-Order Fuctios More patter matchig map Fuctio values ad aoymous fuctios Higher-order fuctios ad curryig foldr foldl Predefied higher-order fuctios 12
The map Fuctio Used to apply a fuctio to every elemet of a list, ad collect a list of results - map ~ [1,2,3,4]; val it = [~1,~2,~3,~4] : it list - map (f x => x+1) [1,2,3,4]; val it = [2,3,4,5] : it list - map (f x => x mod 2 = 0) [1,2,3,4]; val it = [false,true,false,true] : bool list - map (op +) [(1,2),(3,4),(5,6)]; val it = [3,7,11] : it list What is the type of map? The map Fuctio Is Curried The foldr Fuctio - map; val it = f : ('a -> 'b) -> 'a list -> 'b list - val f = map (op +); val f = f : (it * it) list -> it list - f [(1,2),(3,4)]; val it = [3,7] : it list Use map fuctio whe the result is a list of the same legth with the parameter Used to combie all the elemets of a list (starts from right to left) For example, to add up all the elemets of a list x, we could write foldr (op +) 0 x It takes a fuctio f, a startig value c, ad a list x = [x 1,, x ] ad computes: f x f x, f x, f x c ( ( ( ( )) )) 1, 2 1, So foldr (op +) 0 [1,2,3,4] evaluates as 1+(2+(3+(4+0)))=10 Foldr: examples Fuctio start_value list - foldr (op +) 0 [1,2,3,4]; val it = 10 : it - foldr (op * ) 1 [1,2,3,4]; val it = 24 : it - foldr (op ^) "" ["abc","def","ghi"]; val it = "abcdefghi" : strig - foldr (op ::) [5] [1,2,3,4]; val it = [1,2,3,4,5] : it list The foldr Fuctio Is Curried - foldr; val it = f : ('a * 'b -> 'b) -> 'b -> 'a list -> 'b - foldr (op +); val it = f : it -> it list -> it - foldr (op +) 0; val it = f : it list -> it - val addup = foldr (op +) 0; val addup = f : it list -> it - addup [1,2,3,4,5]; val it = 15 : it 13
The foldl Fuctio The foldl Fuctio Used to combie all the elemets of a list Same results as foldr i some cases - foldl (op +) 0 [1,2,3,4]; val it = 10 : it - foldl (op * ) 1 [1,2,3,4]; val it = 24 : it To add up all the elemets of a list x, we could write foldl (op +) 0 x It takes a fuctio f, a startig value c, ad a list x = [x 1,, x ] ad computes: f x f x, f x, f x c ( ( ( ( )) )), 1 2 1, So foldl (op +) 0 [1,2,3,4] evaluates as 4+(3+(2+(1+0)))=10 Remember, foldr did 1+(2+(3+(4+0)))=10 The foldl Fuctio foldl starts at the left, foldr starts at the right Differece does ot matter whe the fuctio is associative ad commutative, like + ad * For other operatios, it does matter - foldr (op ^) "" ["abc","def","ghi"]; val it = "abcdefghi" : strig - foldl (op ^) "" ["abc","def","ghi"]; val it = "ghidefabc" : strig - foldr (op -) 0 [1,2,3,4]; val it = ~2 : it - foldl (op -) 0 [1,2,3,4]; val it = 2 : it Exercises (Weber, Ch. 9) Exercise 3. Write a fuctio squarelist of type it list -> it list that takes a list of itegers ad returs the list of squares of those itegers. Exercise 17. Write a fuctio max of type it list ->it that returs the largest elemet of a list. Your fuctio does ot eed to behave well if the list is empty. 14