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
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:
- 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).
II. 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).
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) } } }