# Lab Exercise 3 (Higher Order Functions for List Comprehension) ### Lists in Haskell Before you start implementing the functions in this exercise, you need to understand how lists work in Haskell. Haskell lists are written like a list in math. The Haskell list: ```Haskell [1,2,3,4,5] ``` is basically equivalent to the list: $$ [1,2,3,4,5] $$ One of the most important things about lists is that you can access the list as a whole and you can access the elements inside the list. One thing you can do is you can concatenate lists using the **`++`** function: ```Haskell ghci> [1,2,3,4,5] ++ [6,7,8] [1,2,3,4,5,6,7,8] ``` You can find the length of the list using the **`length`** function: ```haskell ghci> length [1,2,3,4,5] 5 ``` These are the different ways you can access the elements of the list and the sublists in the list: **`head`** takes a list and returns the first element of the list ```haskell ghci> head [1,2,3,4,5] 1 ``` **`tail`** takes a list and returns the same list except the first element of the list ```haskell ghci> tail [1,2,3,4,5] [2,3,4,5] ``` **`init`** takes a list and returns the same list except the last element of the list ```haskell ghci> init [1,2,3,4,5] [1,2,3,4] ``` **`last`** takes a list and returns the same list except the last element of the list ```haskell ghci> last [1,2,3,4,5] 5 ``` Using these functions you can traverse a list using the head-tail recipe. For example, if you want to add 1 to each of the elements of the array: ```haskell addone :: [Int] -> [Int] addone l = if length l == 0 then [] else [(head l) + 1] ++ addone (tail l) ``` Let's dissect this function one by one, for the first line you can see the type signature `[Int]->[Int]` meaning `addone` accepts a list of `Int`s and returns a list of `Int`s. Any type `a` surrounded by brackets is a list of `a`s (`[a]` is a list of `a`'s, `[Char]` is a list of `Chars`, `[[Int]]` is a list of `[Int]`s or a list of list of `Int`s). In the second line were binding the list we are passing to `l`. The third line refers to the base case, this happens when the list is empty. When the list is empty we return `[]` which refers to an empty list. And finally the last line refers to the general case. Here we are see the subexpression `[(head l) + 1]` which is a list containing one element namely, the first element of the list plus 1. And then we are concatenating this one element list to the result of the call `addone (tail l)` which is a recursive call to the rest of add one to the `tail` of l (or the rest of `l`). Assuming `addone` works perfectly, the recursive call `addone (tail l)` will return the tail of the `l` but the elements are added with one. By concatenating `[(head l) + 1]` with the result of this recursive call, we complete the desired result. - Implement the higher order functions, `my_map`,` my_filter`, and `my_foldl` and `my_foldr`, `my_zip` - **`my_map :: (a -> b) -> [a] -> [b] `** - The `map` function accepts a function $f$ and a list (with elements of type `A`) $l=[l_1,l_2,l_3,...,l_n]$. It returns the list (with elements of type `B`): $l'=[f(l_1),f(l_2),f(l_3),...,f(l_4)]$. The new list `map` produces is a list which is the image of `l` from the function `f`. - **`my_filter :: (a -> Bool) -> [a] -> [a] `** - The `filter` function accepts a predicate $f$ and a list $l=[l_1,l_2,l_3,\cdots,l_n]$. `filter` returns a new list $l'$ such that the contents satisfy $f(l_i)$ is true, retaining the order it appears in $l$. - **`my_foldl :: (a -> a -> a) -> a -> [a] -> a`** - The `foldl` function accepts a function $f$, a list $l=[l_1,l_2,l_3,...,l_n]$ and an initial value $u$. The `foldl` function returns the value $f( f(f(f(u,l_1),l_2),l_3), l_n)$. - **`my_foldr :: (a -> a -> a) -> a -> [a] -> a`** - The `foldr` function accepts a function $f$, a list $l=[l_1,l_2,l_3,...,l_n]$ and an initial value $u$. The `foldr` function returns the value $f(l_1,f(l_2,f(l_3,f(l_n,u))))$. - **`my_zip :: (a -> b -> c) -> [a] -> [b] -> [c]`** - THe `zip` function accepts a function $f$ and two lists $l=[l_1,l_2,l_3,...,l_n]$, $m=[m_1,m_2,m_3,...,m_n]$ and returns a new list, $k=[f(l_1,m_1),f(l_2,m_2),f(l_3,m_3),\cdots,f(l_n,m_n)]$ - Without using loops (use the functions above instead), create the following functions. - Given a list of numbers, return the sum of the squares of the numbers - Given three lists, a list of first names, A, a list of middle names B, and a list of surnames C. Return a list of whole name strings (list of chars) (`[firstname] [middle initial]. [lastname]`) where the length of the string (including spaces and period) is an even number. Example ```haskell ghci> wholeName ["Foo", "Bar", "Foo"] ["Middle", "Center", "Name"] ["Lastn", "Surname", "Abcd"] ["Foo M. Lastn", "Bar C. Surname"] ``` ("Foo S. Abcd" is filtered out because it has 11 characters)