3. Higher-order functions

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).

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).

def foldWith (op: (Int,Int) => Int)(start: Int, stop: Int): Int = {
  def tail_fold(crt: Int, acc: Int): Int  = ???
  ??
}

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.

def foldConditional(op: (Int,Int) => Int, p: Int => Boolean)(start: Int, stop: Int): Int = ???

3.3. [should be revised] Let $ count_k(n) = k + 2k + 3k + \ldots x*k$ , with $ x*k \leq n$ be the sum of all multiples of $ k$ within the range 1,n. Write a function alldivs which computes the sum: $ count_1(n) + count_2(n) + \ldots + count_k(n)$ . (Hint, use foldConditional).

def alldivs(n: Int): Int = ???

3.4. Write a function foldMap which takes values $ a_1, a_2, \ldots, a_k$ from a range and computes $ f(a_1)\;op\;f(a_2)\;op\;\ldots f(a_k)$ .

def foldMap(op: (Int,Int) => Int, f: Int => Int)(start: Int, stop: Int): Int = ???

3.5. Write a function which computes $ 1 + 2^2 + 3^2 + \ldots + (n-1)^2 + n^2$ using foldMap.

def sumSquares(n: Int): Int = ???

3.6. Write a function hasDivisor which checks if a range contains a multiple of k. Use foldMap and choose f carefully.

def hasDivisor(k: Int, start: Int, stop: Int): Boolean = ???

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 $ (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:

def integrate(f: Double => Double)(start: Double, stop: Double): Double = ???