In the previous chapters, you created your own types. Now, it’s time to learn what classes are in Haskell and how to work with them. In this chapter, you’ll learn about the standard classes and then how to create your own classes.
Standard Classes
Eq is used when you work with == (is equal) and /= (is not equal).
Ord is used when you work with the operators <, <=, >, and >= and the functions min, max, and compare.
Enum is used in enumerations and lets you use syntax such as [Red .. Yellow].
Read includes the function read, which takes a string as a parameter and parses it into a value.
Show includes the function show, which takes a value as a parameter and converts it to a string.
Bounded is used in enumerations and includes the functions minBound and maxBound.
Do you remember in Chapter 4 when you used the command deriving followed by one of the previous classes? You did that because you wanted your type to use functions that actually belong to these classes. For example, to compare two dates of type DateInfo, you used deriving Eq. That allowed you to write myDate2 == myDate1.
The Eq Class
This says that the == has the type a->a->Bool for every type a that is an instance of the class Eq.
In the previous code, we defined the type MyType and then made it an instance of Eq. Further, we said that two values of type MyType are equal (==) if the string of the first value is equal to the string of the second value and the integer of the first value is equal to the integer of the second value. It worked. Observe that you use /= even if you don’t define it in the instance declaration of MyType; this is because Haskell knows how to automatically deduce it from the definition of ==.
Inheritance
All types you define should be an instance of Eq and even Show or Ord. When the definitions of methods of these classes are evident, then you can use deriving, as in Chapter 4. In this way, you avoid having to write complex definitions. But you can derive just some of the standard classes: Eq, Show, Ord, Enum, Bounded, Read.
This definition is from Prelude,3 and the multiple inheritance is marked by the inherited classes in the parentheses.
instance: You declare parametrized types.
class: You can add constraints, different from the ones in the class definition, in method signatures.
data: This constrains the constructor signatures.
In our examples, we used three definitions marked by the keywords class, data, and instance. In fact, these are separate, and there isn’t any rule that specifies how you should group them.
Classes are not types; they are categories of types, which means that an instance of a class is a type (not a value!).
You can’t define an instance of a class from type synonyms defined with the keyword type.
In the examples in this section, you saw that you can test whether two values are equal for different types. For example, you can test whether two integer values are equal, you can test whether two string values are equal, and you can test whether two values of type MyType are equal. So, you can apply the == operator in different types. This behavior is known as overloading (or less commonly known as ad hoc polymorphism ).
Creating Your Own Type Class
Advanced Type Classes
Language extensions enable features of Haskell that are useful in certain contexts. In this example, we needed multiparameter type classes. In addition, we used flexible instances, which allows a type parameter to occur twice in a type class instance (for Set [c] c).
In the previous definition, | a -> b means “a uniquely identifies b.” In other words, for a given b, it will be just one a.
You can add as many constraints as you want (of course, they need to make sense) to a class definition, and in a multiparameter class you can use more than two parameters.
Maybe, Just, and Nothing
Nothing: When constructed with Nothing, Maybe is defined as a constant that becomes a member of Maybe a, for all types a, because Nothing doesn’t take a parameter type;.
Just a: When constructed with Just, Maybe is used as a type parameter a; in this scenario, Just behaves as a function from a to Maybe a, meaning its type is a-> Maybe a.
Maybe is mostly used to extend types with the Nothing value, i.e., the absence of a value. This approach prevents errors. In other programming languages, the “no value” is treated with a NULL reference .
Functor
The type class Functor provides a way to make the operations from a base type work with a new type constructed by transforming the base type into the new one. Functor contains the function fmap, which is used to map the function that takes values from the base type with functions that take values from the new type.
In the first branch, there is no value, so return Nothing; in the second branch, there is the value a, so apply the function f to a.
For example, if you work with a value valueI of type Maybe Integer and a function f that goes from an integer to other integer (in other words, Int -> Int), then you can use fmap f valueI to apply f directly on the Maybe Integer value. When using Maybe, it’s safe to think there is nothing to worry about if it didn’t get a value.
Summary
What standard classes Haskell has and what the class hierarchy looks like
How to inherit standard classes
How to define your own type classes and how to avoid common mistakes in class definitions
What language extensions are and when you can use them
What Maybe, Just, and Nothing are and how can you use them with Functor
References
- 1.
A. Serrano Mena. Beginning Haskell: A Project-Based Approach (Apress, 2014)
- 2.
B. Heeren and J. Hage, “Type class directives,” International Workshop on Practical Aspects of Declarative Languages (Springer, 2005)
- 3.
W. Kahl and J. Scheffczyk. “Named Instances for Haskell Type Classes,” in proceedings of the 2001 Haskell Workshop, UU-CS-2001-23 (Tech. Rep., 2001)
- 4.
Predefined types and classes, https://www.haskell.org/onlinereport/basic.html#standard-classes
- 5.
- 6.
Type classes and overloading, https://www.haskell.org/tutorial/classes.html
- 7.
Standard Haskell classes, https://www.haskell.org/tutorial/stdclasses.html
- 8.
Type classes, https://www.schoolofhaskell.com/school/starting-with-haskell/introduction-to-haskell/5-type-classes
- 9.
Language extensions, https://wiki.haskell.org/Language_extensions