Lecture 5

### Using These Slides

#### Every slide has a secret note.

• On Chrome: press `F12`, then click Console
• On IE: press `F12`, then click Console
• On Firefox: `Ctrl+Shift+k`

### Shortcut Keys:

 `↓`, `PgDn`, `n`, `j` next slide `↑`, `PgUp`, `p`, `k` prev slide `Esc` enables `ctrl+f` globally

### Review of Homework 4

Write a function to convert units
 A B C D
``````
-- Designed by Matthew R. Bongiovi
-- using guards

convert :: (Double, [Char]) -> (Double, [Char])
convert (x,l)
| (l == "m") = (1.09361 * x,"yd")
| (l == "L") = (0.264172 * x,"gal")
| (l == "kg") = (2.20462 * x,"lb")
| (l == "yd") = (x / 1.09361, "m")
| (l == "gal") = (x / 0.264172,"L")
| (l == "lb") = (x / 2.20462,"kg")
| otherwise = error "Invalid input"
``````

### Data Types

• `Bool` = False | True

• `Int` = -231 ... -1 | 0 | 1 ... 231-1

• `[Char]` = [] | Char : [Char]

• `Double`

### Making Data Types

• for well structured code

• for improving type safety

### `data` keyword

In a new file `MyData.hs`

create a Data type called `MetricUnits`

``````
data MetricUnit = Meter | Liter | KiloGram
``````

MetricUnit is called the type constructor

Everything after the equal sign is called the value constructor

Notice the capitalization!

### What Exactly is a Type?

Let's look at Meter, Liter, and KiloGram

``````
Prelude> :type True
Bool :: True

Prelude> :type Meter
Meter :: MetricUnit

Prelude> :type Liter
Liter :: MetricUnit

Prelude> :type KiloGram
KiloGram :: MetricUnit
``````

Meter has the type MetricUnit

### Remember Show?

`Show` is a Typeclass that enables data to be shown as a String
``````
Prelude> True
True

Prelude> Meter
No instance for (Show MetricUnit) arising from a use of `print'
Possible fix: add an instance declaration for (Show MetricUnit)
``````

Why did we get this error?

### `deriving (Show)`

• GHCi is trying to call the print function

• `print` only works for things that derive Show

• but our MetricUnit doesn't derive Show

``````
data MetricUnit = Meter | Liter | KiloGram  deriving (Show)
``````
F T F Y

### Type Safety

• Haskell programs are type safe.

• We can't use our MetricUnit type unless a function accepts it

So let's make our own function

### Function that uses MetricUnit

Write a simple function that takes in a MetricUnit, and returns its symbol

• Meter → "m"
• Liter → "L"
• KiloGram → "kg"
``````
symbol :: MetricUnit -> String

``````

### Same Function With Guards

Rewrite `symbol` using guards

``````
symbol :: MetricUnit -> String

``````

Try compiling it. What happens?

### `deriving (Eq)`

GHCi is yelling at us because we used '=='

``````
No instance for (Eq MetricUnit) arising from a use of `=='
Possible fix: add an instance declaration for (Eq MetricUnit)
In the expression: x == Meter
``````

So MetricUnit should derive Eq in this case

``````
data MetricUnit = Meter | Liter | KiloGram  deriving (Show, Eq)
``````

## Metric to Imperial

Let's write a `convert` function with our types.

We will convert from Metric to Imperial.

Just like last week's homework

But this time it will be elegant!

1. Define MetricUnit and ImperialUnit

``````
data MetricUnit = Meter
| Liter
| KiloGram
deriving (Show, Eq)

data ImperialUnit = Yard
| Gallon
| Pound
deriving (Show)
``````

2. Create a Measurement Data Type

Look closely. This syntax is new!

``````
data Measurement = MetricMeasurement Double MetricUnit
| ImperialMeasurement Double ImperialUnit
deriving (Show)
``````

`(MetricMeasurement 3.1 Liter) :: Measurement` `(ImperialMeasurement 200 Pound) :: Measurement`

3. Create the `convert` function

``````
convert :: Measurement -> Measurement
``````

Implement it with pattern matching and guards

``````
convert (MetricMeasurement x u)
| u==Meter    = ImperialMeasurement (1.0936*x) Yard
| u==Liter    = ImperialMeasurement (0.2642*x) Gallon
| u==KiloGram = ImperialMeasurement (2.2046*x) Pound
``````
``````
convert (ImperialMeasurement x u)
| u==Yard   = MetricMeasurement (0.9144*x) Meter
| u==Gallon = MetricMeasurement (3.7854*x) Liter
| u==Pound  = MetricMeasurement (0.4536*x) KiloGram
``````
Full code listing here

4. Compile and Test

``````
Prelude> let m = MetricMeasurement 2 Meter

Prelude> convert m
ImperialMeasurement 2.18722 Yard

Prelude> convert (convert m)
MetricMeasurement 2 Meter
``````

## Record Syntax

Remember, Haskell is lazy, and so are we.

Creating getter functions is monotonous!

``````
data Point = Point Double Double

xval :: Point -> Double
xval (Point x _) = x

yval :: Point -> Double
yval (Point _ y) = y
``````

Haskell provides a shortcut called record syntax

``````
data Point = Point { xval::Double, yval::Double }
``````

### Record Syntax Looks Nice

``````
let a = Point 2 3

let b = Point {xval = 2, yval = 3}
``````

There's more to write, but anyone can easily figure out what's going on.

Especially for large data types!

## Type Parameters

Oh yea, even types can have arguments.

``````
data ThreeThings a = ThreeThings a a a  deriving (Show)
``````

`ThreeThings` is bundle of three identical types
``````
Prelude> ThreeThings 1 2 3
ThreeThings 1 2 3

``````

## Modules

We can export useful code to a module

so that other projects can reuse them.

Let's make a module out of our `convert` code.

Step 1

``````
module MyData
(MetricUnit(..),
ImperialUnit(..),
Measurement(..),
convert)
where
``````

No step 2. That was easy!

Note: your file name should be the same as your module name!

## Importing Code

Use `convert` from anywhere!

``````
-- OtherFile.hs
import MyData
``````
``````
-- display a measurement in Metric
reportMeasurement :: Measurement -> String
``````
``````
-- if metric, print out the measurement
reportMeasurement (MyData.MetricMeasurement x u)
= (show x) ++ " " ++ (show u)
``````
``````
-- otherwise if imperial, convert the measurement and try again
reportMeasurement m
= reportMeasurement (convert m)
``````

# Homework

3. ``data Tree = ... ``
5. ``add :: Tree -> Int``