Modelling the World of Blade Runner with Haskell's Type System
Tags: haskell, functional
Published: 2019-11-26 17:31:45


![alt text](https://cdn.studiodaily.com/wp-content/uploads/2018/01/denabase.jpg
 "Image")


If you are starting your Haskell journey I implore you to focus on the type system. 

Types are the roots from which your Haskell knowledge grows.

Haskell has algebraic data types. This is a fancy way of saying that we can create types which are composites of other types. Intuitively we can think of types as sets of values.

Let's model a simplified demography of the fictional Blade Runner universe with algebraic data types.

## Replicants

Replicants are bioengineered beings that are virtually identical to humans. 

Let us define a type representing all models of replicant.
```haskell
newtype Replicant = ReplicantModel SerialNumber deriving Show
```

`Serial Number` is simply a string of characters which represents the unique ID of a given replicant model such as `"N6MAA10816"`.

`deriving Show` at the end there just means "automatically make the values printable".

Now we need a type to represents the identities of our replicants. 

```haskell
newtype SerialNumber = SerialNumber String deriving Show
```

When creating new types using the `newtype` or `data` keywords everything to the left of the `=` in a type declaration lives in world of types. Whereas data constructors are located to the right of the `=` and take other types as parameters. 

In our type declaration `SerialNumber` is a data constructor and has a parameter of type String. 

Meaning give me a value of type String and I will construct a value for you of type `SerialNumber`. 


Data constructors can have no arguments in which case they are called "nullary" data constructors.

It can be confusing to see `SerialNumber String`. 

Whenever we *declare* a data constructor we always give the types of the arguments it takes.

When we want to actually use a data constructor we apply values to it.
```haskell
> SerialNumber "N6FAB61216"
SerialNumber "N6FAB61216"
```

What's in a name? That which we call a rose by any other name would smell as sweet.


Okay so for a type declaration we list the types of arguments for data constructors and when we want
to actually construct data we apply values.

**Types and values exist in different worlds**

The first key to succeeding in any Haskell initiation ritual is to understand whether an expression is a type or a value judging by the context.

So every type declaration gives us a new type constructor and at *least* one new data constructor.

Bearing this in mind lets look at our `Replicant` type again.
```haskell
newtype Replicant = ReplicantModel SerialNumber deriving Show
```

`Replicant` is a type constructor as it is on the left hand side of the `=`. On the right hand of the side in the world of values we have `ReplicantModel` which is a data constructor. Data constructors are just functions.

Let's make a serial number.

```haskell
> SerialNumber
<interactive>: error:
    • No instance for (Show (String -> SerialNumber))
        arising from a use of ‘print’
        (maybe you haven't applied a function to enough arguments?)
    • In a stmt of an interactive GHCi command: print it
```

My mishap is a gift to your understanding. 

Without a concrete value we don't have anything we can print. We only get concrete values from the evaluation of fully applied data constructors.

The key here in that message is that the data constructor `SerialNumber` is only partially applied meaning it has the type of a function.

**Data constructors are just functions.**

Specifically the type signature of the partially applied `SerialNumber` is ```String -> SerialNumber``` 

The data constructor expects a value of type string to be applied to the `SerialNumber` data constructor.

In this context "applied" means that all the parameters to have been given concrete values. In contrast to my mishap where SerialNumber was partially applied.

For example if we have 
```haskell
> add :: Int -> Int -> Int
> add a b = a + b
```

Then we can partially apply `add` 
```haskell 
> let x = add 1
```
Note we can't print functions so we have to bind it to a variable instead.

or we can fully apply `add`
```haskell
> add 1  1
2
```

Just like normal functions, data constructors have can have values "applied" to their parameters too. 

People versed with other weird/normal languages usually refer to this as calling a function with an argument but forget what you know.


Let's birth this new replicant model into the world of values.
```Haskell
> ReplicantModel (SerialNumber "KD6-3.7")
ReplicantModel (SerialNumber "KD6-3.7")
```

## Humans

While we are at it we need a type to identify humans. 

It is customary to give humans a pronouncable name.

```haskell
newtype Name = Name String deriving Show
```

Pay close attention to the fact that both of our type and data constructors are both called "Name". 

Don't let this confuse you. 

The Haskell compiler can infer from the context whether you are in the values world or the types world and will decide which one to use whenever "Replicant" or "Human" is evaluated.

On the left `Name` is a type constructor which represents types. The right hand side has a data constructor, also called `Name` which represents values. 

This happens a lot in Haskell and confuses those starting out.

Now lets make a type to represent humans. Here the `Name` type constructor to delineate the types of values we need to apply to the `Person` data constructor.

```haskell
newtype Human = Person Name deriving Show
```

In order to get a fully applied Person value of type `Human` which we can actually use we apply a value of type Name to our `Person` data constructor.

```haskell
> Person (Name "Deckard")
Person (Name "Deckard"
```

Now we have fully applied our data constructor we have a value of type Human we can actually use. 

We can verify that the type is human with the `:t` command in the Haskell interpreter.

```haskell
> :t Person (Name "Deckard")
Human
``` 

## Citizens 

We can now form a new composite type to represent the set of all species. 

```haskell
data Species = ReplicantSpecies Replicant | HumanSpecies Human deriving Show
```

Since we have two species `Replicant` and `Human`, the Species type has two data constructors. Note the `|` in between them. This intuitively means "either".

In plain english a value of type Species is made up from a value of either type `Replicant` or `Human`.

Time to classify citizens according to their species and their birth year like any caring state does.
```haskell
data Citizen = Citizen Species BirthYear deriving Show
```

Our `Citizen` type has one data constructor also called `Citizen` which has two parameters. The first of which takes a value of type `Species`. The second parameter takes a value of type `BirthYear` 

You might guess what is coming next.

```haskell
newtype BirthYear = Year Int deriving Show
```

So there we have it. Lets create our first citizen on this lonely planet.

```haskell
> let replicant = ReplicantSpecies (ReplicantModel (SerialNumber "LUV"))
> Citizen replicant (Year 2035)
Citizen (ReplicantSpecies (ReplicantModel (SerialNumber "LUV"))) (Year 2035)
```

> "He named you. Must be special." - K

```haskell
> let species = ReplicantSpecies (ReplicantModel (SerialNumber "LUV"))
> :t species
Replicant
```

```haskell
> :t Citizen species (Year 2035)
Citizen
```

There we have it. The best way to learn about the type system is to model your own domains with algebraic data types and play around with them. Use the `:t` command Haskell `ghci` repl to see the types of expressions. 

The next steps are to understand the difference between product versus sum types and what kinds are in Haskell. Grasping both of these ideas will enhance your understanding of this article.


The code in this article is available in the online REPL [here](https://repl.it/repls/TenderBoringScales).