This is an old revision of the document!
4. Higher order functions
4.1. Map, foldl, foldr, filter, zipWith
Map
The function map
has signature: (a→b) → [a] → [b]
. It takes as parameter:
- a transformer function
f :: a→b
- a list of objects of type
a
It returns:
- a list of transformed objects of type
b
4.1.1. Write a function which takes a list of integers and adds 4 to each element.
4.1.2. Write a function which takes a list of strings and adds a whitespace at the beginning of each string.
4.1.3. Write a function which takes a value k, a list of strings and returns a list with the first k characters of each string.
Filter
The function filter :: (a → Bool) → [a] → [a]
takes as parameter:
- a predicate (or condition) of type
(a → Bool)
- a list of elements of type
a
It returns:
- a list of filtered elements using the predicate.
4.1.4. Write a function which removes all strings which are equal to the empty string.
4.1.5. Write a function which takes a list of strings and returns only those which start with a capital.
Foldr
The function foldr
has type (a → b → b) → b → [a] → b
. It takes as parameter:
- a binary operation
a → b → b
. It takes a “list” element of typea
, and an accumulator of typeb
and returns an element of typeb
- an accumulator (or initial value) of type
b
- a list with elements of type
a
It returns:
- a folded (or reduced) value of type
b
.
Example:
foldr (*) 0 [1,2,3] = 1 * (2 * (3 * 0))
4.1.6. Write a function using foldr which computes the product of a list of integers.
4.1.7. Write a function which computes the maximum of a list of positive integers using foldr.
4.1.8. Write a function which concatenates a list of strings using foldr.
Foldl
The function foldr
has type (b → a → b) → b → [a] → b
. It takes as parameter:
- a binary operation
b → a → b
. It takes an accumulator of typeb
, a “list” element of typea
and returns an element of typeb
- an accumulator (or initial value) of type
b
- a list with elements of type
a
It returns:
- a folded (or reduced) value of type
b
.
Unlike foldr, foldl reduces element in a different order: Example:
foldl (*) 0 [1,2,3] = ((0 * 1) * 2) * 3
4.1.9. Write a function which uses foldl to check if an element is member of a list.
4.1.10. Write a function which uses foldl to implement the reversal of a list.
zipWith
4.1.11. Use ghci> :t zipWith
to inspect the type of zipWith
. Think about a possible example to run this function. What does it do?
4.2. Processing using higher-order functions
The following is an input test. You can add more examples to it:
l = ["matei@gmail.com", "mihai@gmail.com", "tEst@mail.com", "email@email.com", "short@ax.ro"]
Use map
, foldr
/foldl
, instead of recursive functions. Wherever possible, use functional composition and closures.
4.2.1. Remove uppercases from emails. (Do not use recursion). To be able to use character functions from the library, add import Data.Char
at the beginning of the program. Use the Internet to find the appropriate character function.
-- write this function as a closure rem_upper =
4.2.2. Write a function which removes emails longer than a given size. Write the function as a functional closure. Use anonymous functions in your implementation, then think about how you can replace them by a functional composition of more basic functions. Hint: Write your code in steps. Start with the basic idea, then think about how you can write it better and cleaner.
longer :: Int -> [String] -> [String] longer x =
4.2.3. Count the number of emails longer than 12 characters. Use a fold, anonymous functions and functional composition.
howmany =
4.2.4. Split the list between first names and email domains. What ingredients (auxiliary functions) are necessary? Use either a fold or a tail-recursive function in your implementation.
names_emails :: [String] -> [[String]] names_emails =
4.2.5. Identify the list of the employed domain names (e.g. gmail.com
). Remove duplicates. Use no recursion and no additional prelude function apart from head
and tail
. Hint think about the sequence of basic operations you want to perform and assemble them using functional composition.
domains :: [String] -> [String] domains =
(!) 4.2.6. In some previous exercise you have, most likely, implemented a split function using foldr
. Implement one with foldl
. Hint: use an example together with the foldl
implementation to figure out what the accumulator should do.
splitl :: String -> [String] splitl =
4.2.7. Write a function which extracts the domains from emails, without the dot part. (e.g. gmail
). Generalise the previous function splitl
to splitBy:: Char → String → [String]
, and use it each time necessary, in your implementation. Hint: Wherever you want to mix pattern matching with guards, start with the patterns first.
domain :: [String] -> [String] domain =