# Organizing values with types in Haskell

A powerful way to manage complexity in a program is to add *context* to values. For example, 1234 could be a plain number that you can do arithmatic on or an apartment number that of course, you cannot do arithmatic on. If we label the value somehow, then we can set some rules on what can or cannot be done with the value. In programming languages, this is done through classifying values into different *types*. Thus, types are collections of related values. Haskell has somewhat unique way to handle types and it makes writing *type safe* programs convenient.

## Basic types

Some languages call these *atomic types*. These are the building blocks of all other types.

### Bool

Collection of logical values. There are only two - `True`

and `False`

### Char

Collection of all unicode values. For example, ‘a’, ‘$’, ‘1’ etc.

### String

Collection of *all* sequences of characters, including empty string. For example, “", “a”, “aloha” etc.

### Int

Finite-precision integers. Range is from $-2^{63}\ to\ 2^{63} - 1$. Efficient than `Integer`

because operations can be performed at hardware level.

### Integer

Infinite-precision integers. Limited only by the amount of memory available.

### Float

Single-precision floating point numbers.

### Double

Double-precision floating point numbers.

*Type notation*

Type notation is of the form `v :: T`

and we say the type with :: replaced with “has type”. For example, we write, ‘o’ :: Char and we say, “o has type char”.

## List types

List is a sequence of elements of the *same* type. Type notation is `[T]`

meaning it is a “list of type T”. For example, `[False, False] :: [Bool]`

. Number of elements in a list is called *length*. Lists can be of finite or infinite lengths and can contain elements of any type. List type does not tell anything about its length.

## Tuple types

Tuple is a sequence of components of possibly *different* types. Type notation `(T1, T2,..., Tn)`

is a *n-tuple* whose $i^{th}$ element has type $T_{i}$. Number of components in a tuple is called its ‘arity’. Like lists, tuples can contain any type but unlike lists, they can only be of finite arity. Also, from their type, one can infer how many components they have. There can be tuples of 0, 2,…, n arity but not of 1 arity because that leads to ambiguity in syntax where parenthesis are also used to control operator precedence. As an example, (True, “hello”) :: (Bool, String).

Lists and tuples provide allow us to create types of arbitrary complexity. For example

```
-- a pair of Bool list and String list
([False], ["hi"]) :: ([Bool], [String])
-- a list of triple of string, list and char
[("car", 4, 'a')] :: [(String, Int, Char)]
```

## Function types

Functions map argument of one type to result of another. Type notation is `f :: T1 -> T2`

, meaning, f is a function that maps arguments of type T1 to results of type T2. Again, there is no restriction on what T1 and T2 should be and thus can be any of the types discussed so far including the function types too! For example,

```
-- a function with tuple as input and tuple as output
absPair :: (Int, Int) -> (Int, Int)
absPair (x, y) = (abs x, abs y)
-- a list of type Bool -> Bool
[not] :: [Bool -> Bool]
```