This is an old revision of the document!


1. Scala syntax, function definition and higher-order functions

Objectives:

  • get yourself familiar with Scala syntax basics
  • practice writing tail-recursive functions as an alternative to imperative loops
  • keep your code clean and well-structured.

Make sure you have done your scala environment setup ready

Create a new Scala worksheet to write your solutions

1.1. Write a tail-recursive function that computes the factorial of a natural number. Start from the code stub below:

def fact (n: Int): Int = {
   def aux_fact(n: Int, acc: Int): Int = 
       if (???) acc
       else ???
   ???
}

1.2. Implement a tail-recursive function that computes the greatest common divisor of a natural number:

def gcd(a: Int, b: Int): Int = ???

1.3. Write a tail-recursive function takes an integer $ n$ and computes the value $ 1 + 2^2 + 3^2 + \ldots + (n-1)^2 + n^2$ . (Hint: use inner functions).

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

Newton's Square Root method

A very fast way to numerically compute $ \sqrt{a}$ , often used as a standard sqrt(.) implementation, relies on Newton's Square Root approximation. The main idea relies on starting with an estimate (often 1), and incrementally improving the estimate. More precisely:

  • Start with $ x_0 = 1$ .
  • Compute $ x_{n+1} = \displaystyle\frac{1}{2}(x_n+\frac{a}{x_n})$

1.4. Implement the function improve which takes an estimate $ x_n$ of $ \sqrt{a}$ and improves it (computes $ x_{n+1}$ ).

def improve(xn: Double, a: Double): Double = ???

1.5. Implement the function nthGuess which starts with $ x_0 = 1$ and computes the nth estimate $ x_n$ of $ \sqrt{a}$ :

def nth_guess(n: Int, a: Double): Double = ???

Note that:

  • for smaller $ a$ , there is no need to compute $ n$ estimations as $ (x_n)_n$ converges quite fast to $ \sqrt{a}$ .

1.6. Thus, implement the function acceptable which returns true iff $ \mid x_n^2 - a \mid \leq 0.001$ . (Hint, google the abs function in Scala. Don't forget to import scala.math._).

  def acceptable(xn: Double, a: Double): Boolean = ???

1.7. Implement the function mySqrt which computes the square root of an integer a. Modify the previous implementations to fit the following code structure:

def mySqrt(a: Double): Double = {
   def improve(xn: Double): Double = ???
   def acceptable(xn: Double): Boolean = ???
 
   def tailSqrt(estimate: Double): Double = ???
 
   ???
}

1.8. (!) Try out your code for: 2.0e50 (which is $ 2.0\cdot 10^{50}$ ) or 2.0e-50. The code will likely take a very long time to finish. The reason is that $ xn^2 - a$ will suffer from rounding error which may be larger than 0.001. Can you find a different implementation for the function acceptable which takes that into account? (Hint: the code is just as simple as the original one).

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

2.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  = ???
  ??
}

2.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 = ???

2.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 = ???

2.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 = ???

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

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

2.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 = ???

2.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 integ
===== III. Scala in practice =====
 
Objectives:
  * See some very simple examples of real world Scala
 
**3.1** Interacting with the filesystem. Scala uses Java implementations for using most of the operating system's functionalities. In the snippet below, we see the usage of the Java File class.
 
<code Scala>
import java.io.File
val someFile = new File("somefile.txt")
val fileSize = someFile.length

For this exercise we will want to implement a function that receives two files and returns the file with the maximum size.

3.2 Starting from the snippet below which defines a main function (the entry point of a program) in Scala. we want to make a standalone program that prints the size of a file given as an argument.

object Main {
  def main(args: Array[String]): Unit = {
    println("Hello, Scala developer!")
    if (args.length == 0) {
        println("No parameter :(")
    } else {
        val filename = args(0)
    }
 }
}