# Haskell/More on datatypes

* More on datatypes
* Intermediate Haskell
* Modules
* Standalone programs
* Indentation
* More on datatypes
* Other data structures
* Classes and types
* The Functor class

## Enumerations

One special case of the data declaration is the enumeration — a data type where none of the constructor functions have any arguments:
You can mix constructors that do and do not have arguments, but then the result is not called an enumeration. The following example is not an enumeration because the last constructor takes three arguments:
As you will see further on when we discuss classes and derivation, there are practical reasons to distinguish between what is and isn't an enumeration.
Incidentally, the Bool datatype is an enumeration:

## Named Fields (Record Syntax)

Consider a datatype whose purpose is to hold configuration settings. Usually, when you extract members from this type, you really only care about one or two of the many settings. Moreover, if many of the settings have the same type, you might often find yourself wondering "wait, was this the fourth or fifth element?" One way to clarify is to write accessor functions. Consider the following made-up configuration type for a terminal program:
You could then write accessor functions, such as:
You could also write update functions to update a single element. Of course, if you add or remove an element in the configuration later, all of these functions now have to take a different number of arguments. This is quite annoying and is an easy place for bugs to slip in. Thankfully, there's a solution: we simply give names to the fields in the datatype declaration, as follows:
This will automatically generate the following accessor functions for us:
This also gives us a convenient update method. Here is a short example for a "post working directory" and "change directory" functions that work on Configurations:
So, in general, to update the field x in a value y to z, you write y { x = z }. You can change more than one; each should be separated by commas, for instance, y {x = z, a = b, c = d }.
Note
Those of you familiar with object-oriented languages might be tempted, after all of this talk about "accessor functions" and "update methods", to think of the y{x=z} construct as a setter method, which modifies the value of x in a pre-existing y. It is not like that – remember that in Haskell variables are immutable. Therefore, using the example above, if you do something like conf2 = changeDir conf1 "/opt/foo/bar" conf2 will be defined as a Configuration which is just like conf1 except for having "/opt/foo/bar" as its currentDir, but conf1 will remain unchanged.

### It's only sugar

You can, of course, continue to pattern match against Configurations as you did before. The named fields are simply syntactic sugar; you can still write something like:
But there is no need to do this.
Finally, you can pattern match against named fields as in:
This matches the variable lh against the localHost field in the Configuration and the variable rh against the remoteHost field. These matches will succeed, of course. You could also constrain the matches by putting values instead of variable names in these positions, as you would for standard datatypes.
If you are using GHC, then, with the language extension NamedFieldPuns, it is also possible to use this form:
It can be mixed with the normal form like this:
(To use this language extension, enter :set -XNamedFieldPuns in the interpreter, or use the {-# LANGUAGE NamedFieldPuns #-} pragma at the beginning of a source file, or pass the -XNamedFieldPuns command-line flag to the compiler.)
You can create values of Configuration in the old way as shown in the first definition below, or in the named field's type, as shown in the second definition:
The first way is much shorter, but the second is much clearer.
WARNING: The second style will allow you to write code that omits fields but will still compile, such as:
Trying to evaluate the unspecified fields will then result in a runtime error!

## Parameterized Types

Parameterized types are similar to "generic" or "template" types in other languages. A parameterized type takes one or more type parameters. For example, the Standard Prelude type Maybe is defined as follows:
This says that the type Maybe takes a type parameter a. You can use this to declare, for example:
The lookupBirthday function takes a list of birthday records and a string and returns a Maybe Anniversary. The usual interpretation of such a type is that if the name given through the string is found in the list of anniversaries the result will be Just the corresponding record; otherwise, it will be Nothing. Maybe is the simplest and most common way of indicating failure in Haskell. It is also sometimes seen in the types of function arguments, as a way to make them optional (the intent being that passing Nothing amounts to omitting the argument).
You can parameterize type and newtype declarations in exactly the same way. Furthermore you can combine parameterized types in arbitrary ways to construct new types.

### More than one type parameter

We can also have more than one type parameter. An example of this is the Either type:
For example:
In this example pairOff indicates how many groups you would have if you paired off a certain number of people for your activity. It can also let you know if you have too many people for your activity or if somebody will be left out. So pairOff will return either an Int representing the number of groups you will have, or a String describing the reason why you can't create your groups.

### Kind Errors

The flexibility of Haskell parameterized types can lead to errors in type declarations that are somewhat like type errors, except that they occur in the type declarations rather than in the program proper. Errors in these "types of types" are known as "kind" errors. You don't program with kinds: the compiler infers them for itself. But if you get parameterized types wrong then the compiler will report a kind error.
* More on datatypes
* Intermediate Haskell
* Modules
* >> Standalone programs
* >> Indentation
* >> More on datatypes
* >> Other data structures
* >> Classes and types
* >> The Functor class
* Haskell
* Haskell Basics
* >> Elementary Haskell
* >> Intermediate Haskell
* >> Monads
* Advanced Haskell
* >> Fun with Types
* >> Wider Theory
* >> Haskell Performance
* Libraries Reference
* >> General Practices
* >> Specialised Tasks