Edit this page Backlinks This page is read only. You can view the source, but not change it. Ask your administrator if you think this is wrong. ====== 6. Classes in Haskell ====== === Default Classes === Last time we've learned how to define our new data types in Haskell. The simpler ones were ''Ordering'' (some "constants"), ''Point Float Float'', and ''Student String String [Float]''. We've seen that we can define recursively monomorphic or polymorphic types, like ''List a'' and ''BTree a''. Today we will use the following data: <code haskell> data List a = Null | Cons a (List a) data BTree a = Void | Node a (BTree a) (BTree a) data Student = Student { first_name :: String, last_name :: String, grades :: [Float] } {-- For Student, we can define it as a 'struct Student' from C. first_name will be a "getter" for our first String. Haskell helps us by defining 3 simple functions for us to extract each member Try :t Student and :t first_name in GHCI and you'll figure it out quickly. --} </code> Now let's check one more interesting concept, Haskell's class system. If //data// can be considered the //class// from Java, then ''class'' could be considered the //interface// from Java. If you're defining a new //data Point//, you probably encountered some problems trying to print it in GHCI. The quick fix would be adding the ''deriving Show'', which will print the data type in a 'default' manner (you can try). But what exactly is this ''Show''? And how can we provide //our Show//? We can look at the Show class in a simplified form: <code haskell> class Show a where show :: a -> String </code> Here ''a'' is a **data**. More precisely, to be able to print any data from Haskell, then it must implement the //show// function. That's why we can consider it an //interface//. Providing our show will be done by enrolling our type in the already existing class Show. Here you have a simple example, in the lab skel you'll see a more complex show, //just for flexing//. <code haskell> -- the type encapsulated in BTree must also be "showable", so we can do (show v) instance (Show a) => Show (BTree a) where show Void = "" show (Node v l r) = "<"++(show l)++(show v)++(show r)++">" </code> 1. Add List and Student to the Show class. You can print them however you want. If you aren't inspired today, you can use the following: * The lists can be the default style -> //[3,4,1,2,]//. * The student can be something like -> //Studentul: ANDREI Alex-Bogdan = [8.5,6.0,8.7]// 2. The default ''=='' that we get from //deriving Eq// will check if 2 objects are identical. For our data, you'll have to provide a custom '==' such that: * list1 == list2 = True if both trees have the same elements, but in any order * tree1 == tree2 = True if both trees have the same elements, but in any order * stud1 == stud2 = True if both students have the same average on their grades, same last_names and same first_names 3. We would like to use ''+'' and ''*'' on lists and trees to add/multiply corespondent elements. Enroll BTree and List in the ''Num'' class to access the + and * functions. If 2 lists or trees aren't at the same size, then we should consider unexisting corespondents as **Null/Void**. Also * Void + Node = Node * Void * Node = Void * same for lists 4. Let's sort students now. Add the student to the ''Ord'' class and provide implementations for ''<''. The criteria will be their grades average, maximum grade, last_name, and first_name alphabetical. We will sort them by rankings. //stud1 < stud2// if //stud1// is better than //stud2// by the above criteria. === Custom Classes === What if we need to create our own classes? For a quick example, we would like a class that tells us if a data type is Empty or not. We will call this class ''IsVoid'' and all types enrolled in this class must implement the ''isVoid'' method. <code haskell> class IsVoid a where isVoid :: a -> Bool instance IsVoid Bool where isVoid False = True isVoid True = False instance IsVoid (BTree a) where isVoid Void = True isVoid _ = False instance IsVoid [a] where isVoid [] = True isVoid _ = False </code> As you can see, now we can add our data types in the new class, but also Haskell's types. The only requirement is that the enrolled type must implement our method.