Differences
This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
fp:lab03 [2021/03/25 14:27] pdmatei |
fp:lab03 [2022/03/18 15:31] (current) pdmatei |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== 3. Recursive functions and tail-end recursion ====== | + | ====== 3. Higher-order functions ====== |
- | ===== 3.1. Pattern matching revisited ===== | + | Objectives: |
+ | * implement and use **higher-order** functions. A **higher-order** function takes other functions as parameter or returns them | ||
+ | * implement **curry** and **uncurry** functions, and how they should be properly used (review lecture). | ||
- | It is likely that in the above implementations you used ''head'' and ''tail'', or branch definitions combined with '_' to solve the exercises. Haskell supports a more elegant means of //value introspection//, called **pattern matching**. For instance, in: | + | **3.1.** Define the function ''foldWith'' which uses an operation ''op'' to reduce a range of integers to a value. For instance, given that ''op'' is addition (+), the result of folding the range 1 to 3 will be 1+2+3=6. ''foldWith'' should be curried (it will take the operation and return another function which expects the bounds). |
- | <code haskell> | + | <code scala> |
- | f [] = ... | + | def foldWith (op: (Int,Int) => Int)(start: Int, stop: Int): Int = { |
- | f (h:t) = ... | + | def tail_fold(crt: Int, acc: Int): Int = ??? |
- | </code> | + | ?? |
+ | } | ||
+ | </code> | ||
- | ''(h:t)'' is a **pattern** which denotes a non-empty list where ''h'' is the first element and ''t'' is the rest of the list. In fact, ''[]'' is also a pattern denoting the empty lists. Patterns are **allways** surrounded by round parentheses. They can also be composite, as in the exercise below: | + | **3.2.** Define the function ''foldConditional'' which extends ''foldWith'' by also adding a predicate ''p: Int => Int''. ''foldConditional'' will reduce only those elements of a range which satisfy the predicate. |
- | 3.1.1. Write a function which returns the number of elements from a list. Use patterns. | + | <code scala> |
- | + | def foldConditional(op: (Int,Int) => Int, p: Int => Boolean)(start: Int, stop: Int): Int = ??? | |
- | 3.1.2. Write a function which takes a list of integer lists, and concatenates them. (E.g. ''f [ [1,2,3],[4,5] ] = [1,2,3,4,5]''). | + | |
- | + | ||
- | 3.1.3 (!) Write the **same** function, this time using only the **cons** ('':'') operator as well as **patterns**. Hint: | + | |
- | <code haskell> | + | |
- | [[1,2,3],[4,5]] = | + | |
- | 1:[[2,3],[4,5]] = | + | |
- | 1:2:[[3],[4,5]] = | + | |
- | 1:2:3:[[],[4,5]] = | + | |
- | 1:2:3:[[4,5]] = | + | |
- | 1:2:3:4:[[5]] = | + | |
- | 1:2:3:4:5:[[]] = | + | |
- | 1:2:3:4:5:[] | + | |
</code> | </code> | ||
- | 3.1.4. Write a function which removes duplicates from a list of integers. | + | **3.3. [//should be revised//] ** Let $math[count_k(n) = k + 2k + 3k + ... x*k], with $math[ x*k \leq n] be the sum of all multiples of $math[k] within the range 1,n. Write a function ''alldivs'' which computes the sum: $math[count_1(n) + count_2(n) + ... + count_k(n)]. (Hint, use ''foldConditional''). |
- | ===== 3.2. Tail-end recursive functions ===== | + | <code scala> |
- | + | def alldivs(n: Int): Int = ??? | |
- | 3.2.1 Solve exercise 3.1.3. using a tail-recursive function. | + | |
- | + | ||
- | 3.2.2. Solve exercise 3.1.4. using a tail-recursive function. | + | |
- | + | ||
- | 3.2.3. Return all duplicates from a list, using a tail-recursive function. E.g., the duplicates from list ''[1,2,3,4,2,4,2,1]'' are ''[2,4,2,1]''. | + | |
- | + | ||
- | ===== 3.3. Strings in Haskell ===== | + | |
- | + | ||
- | In Haskell, strings are implemented as **lists of type** ''Char''. For instance '''a' '' is a char | + | |
- | + | ||
- | 3.3.1. Write a function which takes a list of words and makes the first letter of each word uppercase. (Hint: google a respective function of chars). | + | |
- | + | ||
- | 3.3.2. Write a function which takes a list of words and makes **all** letters uppercase. | + | |
- | + | ||
- | 3.3.3. (!) Write a function which takes a text and a pattern and returns the number of occurrences of the pattern in the text. | + | |
- | Example: | + | |
- | <code haskell> | + | |
- | search "I eat green apples" "eat" = 1 | + | |
- | search "ababaab" "aba" = 2 | + | |
</code> | </code> | ||
- | 3.3.4. (!) What does ''f'', defined in exercise 2.2.4., do (note that ''Matei'' and ''Mihai'' both start with letter 'M')? Write an implementation for ''f''. | + | **3.4.** Write a function ''foldMap'' which takes values $math[a_1, a_2, \ldots, a_k] from a range and computes $math[f(a_1)\;op\;f(a_2)\;op\;\ldots f(a_k)]. |
- | + | <code scala> | |
- | 3.3.5. Write the signature and implement the following function: | + | def foldMap(op: (Int,Int) => Int, f: Int => Int)(start: Int, stop: Int): Int = ??? |
- | <code haskell> | + | |
- | f ["Matei", "Mihai"] ["Popovici","Dumitru"] = [("Matei","Popovici"), ("Mihai","Dumitru")] | + | |
</code> | </code> | ||
- | 3.3.6. Implement the following function: | + | **3.5.** Write a function which computes $math[1 + 2^2 + 3^2 + \ldots + (n-1)^2 + n^2] using ''foldMap''. |
- | <code haskell> | + | <code scala> |
- | f ["Matei", "Mihai"] ["Popovici","Dumitru"] = ["MPopovici", "MDumitru"] | + | def sumSquares(n: Int): Int = ??? |
</code> | </code> | ||
- | 3.3.7. Write a function which takes a list of pairs - student-name and grade, removes those with grades less than 5, splits the name in substrings, and adds one bonus point to people with three names. Example: | + | **3.6.** Write a function ''hasDivisor'' which checks if a range contains a multiple of k. Use ''foldMap'' and choose ''f'' carefully. |
- | <code haskell> | + | <code scala> |
- | f [("Dan Matei Popovici",9),("Mihai",4),("Andrei Alex",6)] = | + | def hasDivisor(k: Int, start: Int, stop: Int): Boolean = ??? |
- | [(["Dan", "Matei", "Popovici"],10),(["Andrei", "Alex"],6)] | + | |
</code> | </code> | ||
+ | **3.7.** We can compute the sum of an area defined by a function within a range a,b (the integral of that function given the range), using the following recursive scheme: | ||
+ | * if the range is small enough, we treat f as a line (and the area as a trapeze). It's area is $math[(f(a) + f(b))(b-a)/2]. | ||
+ | * otherwise, we compute the mid of the range, we recursively compute the integral from a to mid and from mid to b, and add-up the result. | ||
+ | Implement the function ''integrate'' which computes the integral of a function f given a range: | ||
+ | <code scala> | ||
+ | def integrate(f: Double => Double)(start: Double, stop: Double): Double = ??? | ||
+ | </code> |