Objectives:
Create a new Scala worksheet to write your solutions
2.1.1 Write a function apply
that takes an integer and return the result of the applied function on the given integer. Start from the code stub below:
def apply(n: Int, f: Int => Int): Int = { ??? }
2.1.2 Write a function doubler
that returns a function that doubles the input it receives (an integer). Start from the code stub below:
def doubler(): Int => Int = { ??? }
2.1.3 Create a function trycatch
that takes an integer and evaluates its value using the try function. If an error occurs (try function returns 0), the catch function will be called instead.
def trycatch(t: Int => Int, c: Int => Int)(x: Int): Int = { ??? }
2.1.4 Write a function realtrycatch
where t and c take no parameters and produce a result upon evaluation. If an error occurs (try function returns 0), the catch function will be called instead.
def realtrycatch(t : => Int, c: => Int): Int = { ??? }
2.2.1 Define the function foldWith
which uses an operation op
to reduce a range of integers to a value. foldWith
starts with an initial value acc
supplied by the programmer. For instance, given that op
is addition (+), the result of folding the range 1 to 3 will be acc+1+2+3=6. foldWith
should be curried (it will take the operation and return another function which expects the bounds).
def foldWith (acc: Int)(op: (Int,Int) => Int)(start: Int, stop: Int): Int = { def tail_fold(crt: Int, acc: Int): Int = ??? ?? }
2.2.2 Suppose $ x_1, x_2, x_3$ are the only values from a given range. What is the order in which $ +$ is performed, in foldWith(acc)( (x,y) ⇒ x+y)
? Write an alternative implementation for foldWith
which would compute: $ x_1 + (x_2 + (x_3 + acc))$ , in this particular order.
2.2.3 Define the function foldConditional
which extends foldWith
by also adding a predicate p: Int ⇒ Boolean
. foldConditional
will reduce only those elements of a range which satisfy the predicate. The accumulator should not be filtered.
def foldConditional(acc: Int)(op: (Int,Int) => Int, p: Int => Boolean)(start: Int, stop: Int): Int = ???
2.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)$ .
Use the apply
and foldWith
methods. The accumulator should not be transformed by f
.
def foldMap(acc: Int)(op: (Int,Int) => Int, f: Int => Int)(start: Int, stop: Int): Int = ???
2.2.5 Write a function sum
which takes values start, end and computes the sum of numbers between start and end.
Use the curry function foldWith
defined before.
def sum(start: Int, stop: Int): Int = ???
2.3.1 Modify the function below so that it's curry and use it to compute 5*3
def multiply(x:Int, y:Int): Int = x * y
2.3.2 Modify the function below so that it's curry and use it to compare 3 numbers and return the maximum
def compare(x: Int, y: Int, z: Int): Int = { if (x > y && x > z) x else if (y > x && y > z) y else z }
The graph of a function can undergo different geometric transformation such as scaling, shifting, rotating, mirroring and so on. The result of those transformation will also be a function that looks similarly to the original. In this exercice we will particularly work with lines. A line is a linear equation of the form $ f(x) = a*x + b$
2.4.1 Implement a function that shifts a line on Oy axis by a certain amount $ \Delta y$
def shiftOY(line: Double => Double, delta_y: Double): Double => Double = { ??? }
2.4.2 Implement a function that shifts a line on Ox axis by a certain amount $ \Delta x$
def shiftOX(line: Double => Double, delta_x: Double): Double => Double = { ??? }
2.4.3 Implement a function that checks if two lines intersect at an integer value from a given interval
def intersect(line1: Double => Double, line2: Double => Double)(start: Int, stop: Int): Boolean = { ??? }
In a computer, we would like the central processing unit / thread to have predominantly a managerial role.
As a result, by executing intense computation on this branch, we would delay other functionalities or would lock into a specific task instead of scheduling.
To solve this limitation, programmers have created ways ('functional closures
') in which the main thread injects all the needed parameters to functions and then passes them to other threads, from where they can be unpacked and run.
Such an implementation for functional closures is represented by 'zero-parameter lambdas
' where the evaluation is delayed by currying such a function over our method:
// Variation 1 - using zero-parameter lambdas // the type of the target function type Result = Int // a closure is represented as a function that takes zero parameters type Closure = () => Result // type of a demo function type TFun = (Int, Int) => Result // run in thread will call that function to evaluate def run_in_thread(f: Closure): Result = f() // Dummy method used to illustrate the power of currying // "f" in curry_for_thread def process_data(x: Int, y: Int): Int = { println("Hello") x + y } // creates a lambda with zero parameters, thus "delaying" the call of f // "f" in run_in_thread def curry_for_thread(f: TFun, somex: Int, somey: Int): Closure = () => f(somex, somey) val close = curry_for_thread(process_data, 0, 1) // If you run this code into a Scala Worksheet you will see that "Hello" gets printed when calling the function bellow. // This is thanks to the 0 parameter lambda in curry_for_thread that "forces" // another call of the function for it to execute its body. run_in_thread(close)
Keep this example in mind! We will meet with it again in a future laboratory!