# Part 2 - Exercises 1. Predict the type of the following functions and confirm them in the REPL - take care to include the necessary typeclass constraints when necessary: ```haskell pair x y = (x, y) swap (x,y) = (y,x) palindrome w = w == reverse w second xs = head (tail xs) equal x y | x == y = True | otherwise = False max x y = if x >= y then x else y take10 = take 10 filterLT x = filter (< x) filterLT100 = filter (< 100) applyTwo f g x = f (g x) ``` 1. Write down functions that match the declared types, replacing the `undefined` values, and taking advantage of polymorphic constraints when available; it does not matter what the functions actually do, as long as they are type correct: ```haskell copy :: a -> (a, a) copy = undefined mix :: (a, b) -> (c, d) -> ((b, d), (a, c)) mix = undefined apply :: (a -> b) -> a -> b apply = undefined pick :: a -> a -> Bool -> a pick = undefined noFalse :: [Bool] -> Bool noFalse = undefined select :: Eq a => a -> [a] -> [a] select = undefined munge :: (x -> y) -> (y -> (w, z)) -> x -> w munge = undefined madness :: (b -> c) -> d -> (a -> b) -> (a, e) -> (c, d) madness = undefined check :: Eq b => (a -> b) -> a -> b -> Bool check = undefined merge :: (Ord a, Num b) => (a, b) -> (b, a) -> (a, b) merge = undefined i :: a -> a i = undefined c :: a -> b -> a c = undefined ``` 1. The functions `i` and `c` defined above already exist and are included in Prelude. Use Hoogle to find out their names. 1. Using `map`, write a function that, given a list of names, returns the corresponding initials: ```haskell initials :: [[Char]] -> [Char] initials = undefined ``` 1. The function `tail` included in the Prelude produces a list without its first element. If an empty list is given, an exception occurs. Write a variation of this function called `safeTail` that prevents an exception and returns an empty list instead, using a conditional expression (`if then else`). ```haskell safeTail :: [a] -> [a] safeTail = undefined ``` 1. Now write one variation of `safeTail` using guards, and another using pattern matching. 1. Given the list of tuples `records` below, write the `choose` function using `filter` and a lambda expression so that it returns the tuples that have `True` and a number below 10: ```haskell records = [(True,5), (False,7), (True,12), (True,8), (False,15), (True,4)] choose :: (Ord a, Num a) => [(Bool, a)] -> [(Bool, a)] choose = undefined -- choose records should return [(True,5),(True,8),(True,4)] ``` 1. Given the same `records` list above, write a function `transform` using `map` and a lambda expression that extracts the numbers from the tuples and doubles them when they are associated with a `False` value: ```haskell transform :: Num a => [(Bool, a)] -> [a] transform = undefined -- transform records should return [5,14,12,8,30,4] ``` 1. The Luhn algorithm is a simple checksum formula used to validate bank card numbers, and can be described as follows: * consider each digit as a separate number; * moving from right to left, double every other number from second last; * subtract 9 from each number that becomes greater than 9; * add all resulting numbers together; * if the total is divisible by 10, the number is consider valid. First define a function `luhnDouble` that doubles a digit and subtract 9 if the result is greater than 9: ```haskell luhnDouble :: Int -> Int luhnDouble = undefined -- luhnDouble 3 should return 6, and luhnDouble 6 should return 3 ``` 1. Using `luhnDouble`, write the `luhn` function implementing the algorithm deacribed above for the case of 4 digits. To increase readability, use a `where` declarations to compute intermediate results. ```haskell luhn :: Int -> Int -> Int -> Int -> Bool luhn = undefined -- luhn 1 7 8 4 should return True, and luhn 4 7 8 3 should return False ```