CPSC 349 — Creating a "show" FunctionQuestion:
What are the keywords "deriving" and "instance" all about?
The deriving and instance keywords: The "deriving" and "instance" keywords define membership in type classes. "deriving" provides membership with default function definitions, and "instance" provides membership with function definitions you explicitly write. So for example, the type class "Eq" provides equality (==) and inequality (/=) functions for its member types. That is, any data type that is in the class Eq has these two functions defined for it. Most built-in Haskell types (such as String, Int, Float and so on) are in the class Eq so, for example, if I have two variables int1 and int2, that are both of type Int, I am allowed to compare them using "int1 == int2" and likewise, "int1 /= int2". For our own data types that we have created, we may have them derive membership (i.e.: derive default function definitions for (==) and (/=)) from the Eq class, or we may decide that is insufficient, and instead create our own explicit definition. Examples of both may be found in the IO example I posted a couple of weeks ago. The type Node derives default in/equality functions due to the "deriving Eq" clause found immediately under the data type definition. These default functions work by performing the (==) and (/=) on the constituent parts. That is, an equality test on (N city1) and (N city2) is done by testing the first component (here, we have the constructors N and N, so they are always equal), and then testing the second component (here city1 and city2). Since city1 and city2 are just strings (we defined the Node type to be (N String)), and String is already in the Eq class, this can be done. The type Edge, however, has an explicit equality function written for it, a few lines later. That is, we admit Edge as an instance of Eq by providing the necessary function:
instance Eq Edge where
(E s1 e1 w1) == (E s2 e2 w2)
| s1 == s2 && e1 == e2 = True
| s1 == e2 && e1 == s2 = True
| otherwise = False
The inequality test (/=) is by default defined to be the boolean opposite of the
equality test. That is, to resolve (edge1 /= edge2), where (/=) has not been
defined, Haskell replaces the test with (not (edge1 == edge2)).A show function for user-defined data types: Armed with the above knowledge, we may use it to write our own show function for the various data types we have created. I will use the example of Node, recalling its definition "Data Node = N String deriving Eq". The easy way, and one that is perfectly useful for testing purposes, is to have Haskell derive a default show function for Node using the "deriving" keyword:
data Node = N String
deriving (Eq, Show)
To do this requires that all components of the type (in this case, this consists solely of the
datatype String) already be in the class Show. In the case of
String, this is true (String has a built-in show function, which
basically just returns the string itself). All constructors (such as the N) are
already in all of Haskell's built-in classes, and we do not need to worry about
them.Note, however, that while this will be fine for testing, it will not be sufficient for the final output of your program; it does not conform to the output specification posted. If you wish to use show for that (which I do recommend), you will likely want to create your own show functions that do what you want. For the Node type (and most user-defined types), this adds the extra wrinkle of pulling the data out of the type, so the various constructors and so on don't get in the way. We can do this in a very similar manner to the way that we defined the equality function for the Edge type above:
data Node = N String
deriving Eq
...
instance Show Node where
show (N city) = city
The one important thing to recall here is that if we create our own show function in
this manner, we do not use the "deriving" keyword to derive a default function,
because we will then have two show functions for Node that conflict with
each other.Anything more than that, (for example, adding any of your types to other classes, or writing a show function for your various other types), well... that's your job. You should be able to figure out what you want to do from what I've written above. Further reading: For more information about type classes in Haskell, and on creating your own instances, please refer to Chapter 5 (Type Classes and Overloading) in the Haskell tutorial. For more on the standard classes provided by Haskell, and on derived instances, please refer to Chapter 8 (Standard Haskell Classes) in the tutorial. <-- Back to the main CPSC349 page |