Table of Contents

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

Objectives:

Make sure you have done your scala environment setup ready

Create a new Scala worksheet to write your solutions

I. Scala syntax, function definition

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:

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:

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

II. Higher-order functions

Objectives:

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:

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

III. Scala in practice

Objectives:

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.

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