Skip to content

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++.