Data Types
When choosing a programming language, we generally have to consider two things: What tools are there to implement the logic of programs? That's control flow constructs such as case distinctions, recursion and, in imperative languages, loops. You may also have facilities to implement multi-threaded code. The second question is what tools there are to organize the data that the program manipulates. That's the data types that are built into the language or provided by the standard library, and the mechanisms the language provides to define new data types.
Haskell has a lot of data types built in or provided by its standard library. Additional data types are available from third-party packages. We will look at some of them in this book. In this chapter, we will look at how we can define our own data types and how they interact with pattern matching, Haskell's primary tool for implementing case distinctions.
As a short preview, new data types are introduced using the data
keyword. This
is not all that different from defining a class in Java or Python.
As we will discuss, it isn't uncommon to define a type whose runtime
representation is exactly the same as that of an existing type. By making this a
separate type, we ensure that the compiler complains whenever we accidentally
mix up the two types in our program, which usually reflects some logical flaw in
our program. We define these new types with the same runtime representation as
an existing type using newtype
. We could define these types using data
, but
this would lead to the two types not having the same runtime representation and
would incur some runtime overhead.
The final tool we have to define "new" types is the type
keyword. This does
not define a new type at all. It only introduces a second name for an existing
type, a type alias. The original type and the type alias are usable
interchangeably. This is the same as using typedef
in C or C++.