Making Our Own Types and Typeclasses
====================================

Types are defined using the data keyword like so:

> data Bool' = False | True

More complex types may also be defined:

```
 -- Circle x y r
 -- Rectangle x1 y1 x2 y2
 data Shape = Circle Float Float Float |
              Rectangle Float Float Float Float
              deriving Show
```

The `deriving Show` declaration allows the types to be displayed, eg.
given

```
niceRectangle :: Shape
niceRectangle = Rectangle 0 0 3 4
```

Without show, calling `niceRectangle` from the REPL will trigger an
error:

```
ghci> niceRectangle
ERROR - Cannot find "show" function for:
*** Expression : niceRectangle
*** Of type    : Shape
```

With show, calling this from the REPL will show something to the
effect of

```
ghci> niceRectangle
Rectangle 0.0 0.0 3.0 4.0
```

The value constructors (Circle and Rectangle) may be used in pattern
matching. 

```
surface :: Shape -> Float
surface (Circle _ _ r) = pi * r^2
surface (Rectangle x1 y1 x2 y2) = (abs $ x1 - x2) + (abs $ y1 - y2)
```

It's important to understand the distinction between Shape and Circle.
Shape is a type, and Circle is a function producing a value of type
Shape. The fact that a value constructor is a function means it can be
partially applied. This leads to a origin concentric circle function:

> originConcentricCircle :: Float -> Shape
> originConcentricCircle = Circle $ Point 0 0

This new function can be used to generate a sequence of concentric
circles, a la

```
ghci> map originConcentricCircle [1..10]
[Circle (Point 0.0 0.0) 1.0,Circle (Point 0.0 0.0) 2.0,Circle (Point 0.0 0.0) 3.0,Circle (Point 0.0 0.0) 4.0,Circle (Point 0.0 0.0) 5.0,Circle (Point 0.0 0.0) 6.0,Circle (Point 0.0 0.0) 7.0,Circle (Point 0.0 0.0) 8.0,Circle (Point 0.0 0.0) 9.0,Circle (Point 0.0 0.0) 10.0]
```


The `Shape` type may be refined further:

> data Point = Point Float Float deriving (Show)
> data Shape = Circle Point Float |
>              Rectangle Point Point
>              deriving (Show)

This does require changes to `surface`.

> surface :: Shape -> Float
> surface (Circle _ r) = pi * r^2
> surface (Rectangle (Point x1 y1) (Point x2 y2)) = (abs $ x1 - x2) + (abs $ y1 - y2)

These value constructors could be exported via

```
module Shapes
(Point(..)
,Shape(..)
,surface)
where
```

Alternatively, to just allow the use of `Shape`s via auxilliary
functions, export just `Shape` and the desired functions:

```
module Shapes
(Shape
,originConcentricCircle)
where
```

Record syntax
-------------

Instead of a tedious declaration such as

> -- first name, last name, age, height, phone number
> data TediousPerson = TediousPerson String String Int Float String deriving (Show)

> printTediousName :: TediousPerson -> String
> printTediousName (TediousPerson f l _ _ _) = f ++ " " ++ l

Instead, define a `Person` as a *record*:

> data Person = Person { firstName :: String
>               ,lastName :: String
>               ,age :: Int
>               ,height :: Float
>               ,phoneNumber :: String
>               } deriving (Read, Show, Eq)


This defines, for example, a function `firstName`:

```
ghci> :t firstName
firstName :: Person -> String
```

The author:

> me :: Person
> me = Person "Kyle" "Isom" 27 69 ""

Alternatively,

> meToo :: Person
> meToo = Person{firstName="Kyle"
>               ,lastName="Isom"
>               ,age=27
>               ,height=69
>               ,phoneNumber=""
>}

A function for printing names using the record functions:

> printName :: Person -> String
> printName p = (firstName p) ++ " " ++(lastName p)

Type parameters
---------------

Consider a vector:

> data Vector a = Vector a a a deriving (Show)

A few operations defined on vectors:

> vplus :: (Num t) => Vector t -> Vector t -> Vector t
> (Vector i j k) `vplus` (Vector l m n) = Vector (i+l) (j+m) (k+n)

> vectMult :: (Num t) => Vector t -> t -> Vector t
> (Vector i j k) `vectMult` m = Vector (i*m) (j*m) (k*m)

> scalarMult :: (Num t) => Vector t -> Vector t -> t
> (Vector i j k) `scalarMult` (Vector l m n) = i*l + j*m + k*n


Derived instances
-----------------

Haskell can often automatically derive support for 

* Eq
* Show
* Read
* Ord
* Enum
* Bounded

Typically, a record's fields must satisfy the typeclass as well. In
the `Person` type, all of its fields are members of the `Eq`
typeclass, which allows the `Person` type to automatically derive
`Eq`. 

The `read` function provided by members of the `Read` type class
converts a string to some value:

```
ghci> :t read
read :: Read a => String -> a
```

It does require explicit type annotation if the value can't be
inferred from context. 

```
ghci> read "5.0"
ERROR - Unresolved overloading
*** Type       : Read a => a
*** Expression : read "5.0"
ghci> read "5.0" :: Float
5.0
```

We could `read` a `Person`:

> readPerson :: Person
> readPerson = read "Person {firstName=\"Kyle\", lastName=\"Isom\", age=27, height=69, phoneNumber=\"\"}"
