`data` is how data structures are defined.

Data structures have a type name and any number of constructors, special functions that store data.

## Syntax
```haskell
data <type_name> <type_parameters>
  = <constructor>
  | ...
```

### type_name
a PascalCase identifier that is the type of the data structure

### type_parameters
space-separated list of 0 or more generic type variables

### constructor
a PascalCase identifier with 0 or more arguments. This identifier is used as a function that constructs data of type `type_name`.

## Data Structure Types
### Newtype
A newtype is a name for a data structure with one constructor accepting one argument.

Newtypes are used to add or customize behavior for types which can't otherwise be extended.

```haskell
data Identity a = Identity a
```

[[Identity]] is a very common newtype, allowing the use of [[do notation]] without using an actual monad that needs to be evaluated like [[Effect]] or [[Maybe]].

This pattern is so common and useful that there is a special subset of `data` structures specifically for writing newtypes; the [[newtype]] keyword.

### Sum Type
A [sum type](https://en.wikipedia.org/wiki/Tagged_union) is a data structure that may be in one of multiple possible states.

When you have an instance of a sum type and you want to handle a particular case, you need to exhaustively handle all cases.

```haskell
data Maybe a = Just a | Nothing
```

[[Maybe]] and [[Either]] are common examples of sum types, and their "or-ness" is what gives them their meaning.

### Product Type
While sum types encode "A or B", product types encode "A and B."

```haskell
data Tuple a b = Tuple a b
```

[[Tuple|Tuples]], for example, are encoded this way. In order to construct a tuple, you need to provide both fields.

## Examples

#### No constructors
```haskell
data Void
```
[[Void]] has no constructors, so it can **never** be created.

#### One constructor
```haskell
data IntNonZero = INZ Int
```

> [!hint]- Constructor Naming
> In this example I've named the type `IntNonZero` and its constructor `INZ` differently to show that constructors do not have to have the same name as the type they construct.
>
> If this were an actual type, I would probably name the constructor `IntNonZero` instead of `INZ`, though.

Here, we create a type `IntNonZero` that can be created by calling `INZ :: Int -> IntNonZero` with an [[Int]].

#### Multiple constructors
```haskell
data AnimalType = Cow | Dog | Cat
```

`AnimalType` has 3 possible constructors: `Cow`, `Dog` and `Cat`.

#### Parameterized
```haskell
data Identity a = Identity a
```

Declare a type [[Identity]], generic over some other type `a`.

You can create one with the constructor `Identity`, e.g.

```haskell
Identity 1
Identity 1.0
Identity ""
Identity []
Identity unit
```
