# teaching machines

## CS 330 Lecture 21 – More Recursion and Pattern Matching

Dear students,

Today we solve more problems in Haskell together. Along the way we will discover some of the peculiarities of functional programming, like the lack of iteration, the supremacy of recursion, and the beauty of pattern matching:

Here are the problems we’ll solve:

1. Last time we started to write a function to determine if a list contains an element. Our first attempt used simple conditionals and recursion:
```contains :: [a] -> Bool
contains needle haystack =
if haystack == [] then
False
else
if head haystack == needle then
True
else
contains needle \$ tail haystack```
This is okay, but Haskell sports a really nice guard syntax that shows the decision structure that we often see in mathematics:
```contains needle haystack
| head haystack == needle = True
| otherwise = False```
A little shorter, right? Well, we also have a `case` statement in Haskell, which allows us to use pattern matching:
```contains needle haystack =
case haystack of
[] -> False
(first : rest) -> first == needle || contains needle rest ] This doesn't seem better than the guards. However, Haskell allows us to rewrite this structure in a more digestable way: [code
contains _ [] = False
contains (first:rest) = first == needle || contains needle rest```
Under the hood these seemingly multiple definitions of `contains` get turned into a case statement. But this syntax lets us focus on one case at a time. In my opinion, it is the pinnacle of clarity.
2. Let’s write `sum` to sum up a list of numbers in a similar way:
```sum [] = 0
sum (first:rest) = first + sum rest```
3. Let’s write `head'`:
```head' [] = error "Can't decapitate the empty list!"
Notice that in the second case we don’t use `rest` at all. Haskell lets us acknowledge its irrelevance by blanking out the identifier name:
`head' (first:_) = first`
This feature is not unique to Haskell. Check out this from Ruby:
```def foo
[1, 2]
end
first, second = foo
```
The array returned by `foo` is destructured into `first` and `second`. Suppose we don’t need `second`:
```first, _ = foo
```
If we didn’t explicitly express `_`, no destructuring would take place, and `first` would hold `[1, 2]`. C++ also allows us to disregard parameters simply by not naming them in the formal parameters:
```void foo(int a, int) {
return f(a);
}
```
Why would you ever write a function to take in a certain number of parameters and then completely ignore one? That sounds ridiculous. Except when you get into the world of inheritance, where you don’t get to choose your parameters.
4. Let’s write `tail'`:
```tail' [] = error "Can't detorso the empty list!"
tail' (_:rest) = rest```
5. Let’s write `belows`, which gives us back all elements of a list less than some threshold:
```belows [] = []
belows threshold (first:rest)
| first < threshold = first : belows rest
| otherwise = belows rest```
6. Let’s write an enum-like structure:
`data Color = Red | Green | Blue | Yellow | Orange`
7. Let’s write `eval`, which evaluates an expression, just like we saw on the midterm. First, we need to create a hierarchy:
```data Expr =
ExprInt Integer |
ExprNegate Expr |
ExprMultiply Expr Expr |
Now we can define `eval`:
```eval :: Expr -> Integer
eval (ExprInt n) = n
eval (ExprNegate e) = -eval e
eval (ExprMultiply e1 e2) = eval e1 * eval e2
eval (ExprAdd e1 e2) = eval e1 + eval e2```
We need a crazy expression to test this on. How about `(17 + 1) * -(0 + 2))`?
`eval (ExprMultiply (ExprAdd (ExprInt 17) (ExprInt(1))) (ExprNegate (ExprAdd (ExprInt 0) (ExprInt 2)))`
8. Let’s write `contains` again, but this time let’s operate on a binary search tree:
```data Tree a =
Leaf a |
Branch (Tree a) a (Tree a)

has :: Ord a => a -> Tree a -> Bool
has needle (Leaf value) = value == needle
has needle left value right
| target == needle = True
| target < needle = has needle left
| otherwise = has needle right```

See you next time, when we discuss the various ways we can define functions in Haskell!

Sincerely,