# Lecture 4: Secret Code, User-defined datatypes

```
{-# OPTIONS -Wall -fno-warn-type-defaults #-}
module Lec4 where
```

```
import Prelude hiding (Maybe,Just,Nothing,Either,Left,Right)
import Test.HUnit
```

REMINDER: HW #1 is due tomorrow at 8PM! HW #2 will be available on Wednesday.

# Back to Secret Code

Recall the plan that Chris was working through with you last Wednesday:

We will develop a Haskell program to encode files from disk.

We will modify the program so that it can both encode and decode files.

According to Chris, you worked through the first part of the SecretCode, but did not finish it. We'll pick up there.

# User-defined datatypes

So far, we've mostly talked about how to use the types that appear in the Haskell standard library. We also discussed a few type synonyms, like

` type XY = (Double,Double)`

from the last lecture, but we haven't described any ways to define really *new* types.

As a motivating example, suppose you are writing an application that deals with calendars and you need to represent the days of the week. You might be tempted to use `String`

s or `Int`

s, but both of these choices have issues. If you use

type Day = String

there will be lots of `Day`

s that don't actually represent real days. Also, you will need to devise and adhere to some sort of standardization - is Monday represented by "Monday", "monday", "MONDAY", or "Mon"? Should you handle more than one?

The choice

type Day = Int

has similar problems. There are lots of Ints that won't represent valid days. Also you'll have to remember whether you pick Sunday or Monday to be the first day of the week, and whether it is represented by 0 or 1.

Haskell has a better solution: user-defined datatypes:

```
data Day = Monday
| Tuesday
| Wednesday
| Thursday
| Friday
| Saturday
| Sunday
```

The new values (`Monday`

, `Tuesday`

, etc.) are called "constructors". This is a very simple example of a datatype (basically just an enumeration), but we'll see more examples in a minute.

We can define functions on datatypes by pattern matching! For example:

```
nextWeekday :: Day -> Day
nextWeekday Monday = Tuesday
nextWeekday Tuesday = Wednesday
nextWeekday Wednesday = Thursday
nextWeekday Thursday = Friday
nextWeekday Friday = Monday
nextWeekday Saturday = Monday
nextWeekday Sunday = Monday
```

This is great. Now we don't have to worry about the difference between "Monday" and "monday" or which Int corresponds to which day. If we make a typo (for example, write Frday instead of Friday), the compiler will warn us *at compile time*. And if we forget to handle one of the days in some function, the compiler will warn us about that too (inexhaustive pattern match warning).

Let's write one more function on `Day`

s - we can now easily compute when a package will arrive by "two day" shipping:

```
twoBusinessDays :: Day -> Day
twoBusinessDays = undefined
```

Datatypes can hold data, too. For example, here is a datatype for representing shapes:

```
data Shape =
Circle Float Float Float
| Rectangle Float Float Float Float
```

Here, `Circle`

and `Rectangle`

are the constructors - every `Shape`

must be one or the other. Each constructors has some arguments:

A

`Circle`

is specified by three`Floats`

. These represent the x and y coordinates of the center and the radius.A

`Rectangle`

is specifed by four`Floats`

. The first two are the coordinates of the lower left corner, and the second two are the coordinates of the upper right corner.

We can pattern match on shapes. For example, here is a function that computes the area of any `Shape`

:

```
area :: Shape -> Float
area = undefined
```

Note that constructors are first-class Haskell values just all the other values we have seen. Like any value, they have types.

For example the types of `Monday`

and `Tuesday`

shouldn't surprise you:

```
Monday :: Day
Tuesday :: Day
```

The constructors that take arguments have *function* types. For example, you must apply `Circle`

to three `Float`

s to get a `Shape`

:

```
Circle :: Float -> Float -> Float -> Shape
Rectangle :: Float -> Float -> Float -> Float -> Shape
```

# Recursive Types

Datatypes can be defined recursively. That is, their constructors can take other elements of the same type as arguments.

For example, here is one way to define the type of natural numbers:

```
data Nat = Zero
| Succ Nat
```

Every natural number is either Zero, or the successor of some other natural number. For example, we represent 2 as:

```
natTwo :: Nat
natTwo = Succ (Succ Zero)
```

We could write a function convert `Nat`

s to `Int`

s. Of course, we'll do it with pattern matching and recursion:

```
natToInt :: Nat -> Int
natToInt = undefined
```

We could also define a function to add two natural numbers:

```
natPlus :: Nat -> Nat -> Nat
natPlus = undefined
```

Do they work?

```
natToIntTests :: Test
natToIntTests = TestList [ natToInt Zero ~?= 0,
natToInt (Succ (Succ (Succ Zero))) ~?= 3 ]
```

```
natPlusTests :: Test
natPlusTests =
TestList [ natToInt (natPlus (Succ (Succ Zero)) Zero) ~?= 2,
natToInt (natPlus (Succ Zero) (Succ (Succ Zero))) ~?= 3]
```

As another example, we could define a type representing lists of integers:

```
data IntList = INil
| ICons Int IntList
```

So that the list 1,2,3 is represented as:

```
oneTwoThree :: IntList
oneTwoThree = ICons 1 (ICons 2 (ICons 3 INil))
```

For comparison with Haskell's built-in lists, it might help to think of this as:

```
oneTwoThree' :: IntList
oneTwoThree' = 1 `ICons` (2 `ICons` (3 `ICons` INil))
```

We can define functions by recursion on these too, of course:

```
sumOfIntList :: IntList -> Int
sumOfIntList = undefined
```

# Polymorphic Datatypes

It would sure be annoying to have a seperate kind of list for each type of data! Luckily, we know Haskell's list type is polymorphic - you can have a list of type `[a]`

for any `a`

.

Users can define polymorphic datatypes too. For example, here is the definition of the `Maybe`

type that we've used in past lectures:

`data Maybe a = Nothing | Just a`

Notice that the type `Maybe`

itself takes an argument now - the type variable `a`

. We're allowed to use that type variable in the constructors. So `Just`

is a constructor that can be applied to values of any type and will create a `Maybe`

of the same type:

`Just :: a -> Maybe a`

Thus, `Just`

and `Nothing`

work at any type:

```
justThree :: Maybe Int
justThree = Just 3
```

```
noInt :: Maybe Int
noInt = Nothing
```

```
justTrue :: Maybe Bool
justTrue = Just True
```

A number of other polymorphic datatypes appear in the standard library. For example, here's a datatype that's useful when you want to carry around values that could have either of two types:

`data Either a b = Left a | Right b`

`Either`

is often useful for error handling. Sometimes returning a `Maybe a`

isn't quite good enough because you'd like to give a helpful error message. `Either String a`

works a little better - you can use `Left msg`

in the case of an error, and `Right v`

in case things are... all right.

For example, here's a safer division function:

```
safeDiv :: Int -> Int -> Either String Int
safeDiv _ 0 = Left "You can't divide by zero, silly."
safeDiv x y = Right $ x `div` y
```

Of course, Either is more useful when things can go wrong in more than one way.

# Trees

OK, now let's play a bit with a bigger example: trees. Here's one way to define binary trees that have data at the internal nodes in Haskell:

`data Tree a = Leaf | Branch a (Tree a) (Tree a)`

For example, we can represent the following tree:

```
5
/ \
2 9
/ \ \
```

1 4 7

Like this:

```
exTree :: Tree Int
exTree = Branch 5 (Branch 2 (Branch 1 Leaf Leaf) (Branch 4 Leaf Leaf))
(Branch 9 Leaf (Branch 7 Leaf Leaf))
```

We can write simple functions by recursion:

```
treePlus :: Tree Int -> Int -> Tree Int
treePlus = undefined
```

```
infixOrder :: Tree a -> [a]
infixOrder = undefined
```

Of course, what we should really do is reimplement our higher-order patterns for trees!

```
tMap :: (a -> b) -> Tree a -> Tree b
tMap = undefined
```

The type of fold will have to change a little bit. Now the function that tells us how to combine the current element with the recursive result will have to take two results - one for each branch!

```
tFold :: (a -> b -> b -> b) -> b -> Tree a -> b
tFold = undefined
```

Now, let's reimplement infixOrder:

```
infixOrder' :: Tree a -> [a]
infixOrder' = tFold undefined []
```

And we can get the other orderings just as quickly!

```
prefixOrder :: Tree a -> [a]
prefixOrder = tFold undefined []
```

```
postfixOrder :: Tree a -> [a]
postfixOrder = tFold undefined []
```

[1] This example taken from "Learn You a Haskell for Great Good". http://learnyouahaskell.com/

```
main :: IO ()
main = putStrLn "This is Lec4"
```

## News :

Welcome to CIS 552!

See the home page for basic
information about the course, the schedule for the lecture notes
and assignments, the resources for links to the required software
and online references, and the syllabus for detailed information about
the course policies.