Scala Lesson "Currying" - scala

I'm newbie with Scala, I'm having issue with currying and can't understand of how below code answer is 144. Hope you guys can help me here.
Thanks
def product (f: Int => Int)(a: Int, b: Int) : Int =
if(a>b) 1
else f(a) * product(f)(a + 1, b)
product(x => x * x)(3, 4) //answer = 144

Here is nothing related with currying. You could rewrite your product method like this:
def product(f: Int => Int, a: Int, b: Int) : Int =
if(a>b) 1
else f(a) * product(f, a + 1, b)
val f = (x: Int) => x*x
product(f, 3, 4) // still 144
You could replace product(f, a, b) with f(a) * product(f, a+1, b) (in case a <= b) or with 1, you could also replace f(a) with a*a:
product(f, 3, 4) ==
9 * product(f, 4, 4) ==
9 * ( 16 * product(f, 5, 4) ) ==
9 * ( 16 * 1 ) ==
144

First argument of this method is a function that maps integer to integer, ie. in given example, it squares the number passed to it.
Function 'product' then uses that function (passed as first parameter), and applies it to first argument ('a') and multiplies that result to recursive call to 'product' with same 'f', but with first argument incremented.
As you can notice, parameter named 'b' doesn't play any computational role, other than limit to number of executions of function 'product'.
So, to resolve that call of 'product', we begin with 'a = 3, b = 4'.
First, as 'a' is less than or equal to 'b', we go to else branch where we square (apply 'f') first parameter 'a' (which gives 9), and then multiply that with 'product(f)(4, 4)'.
We also go to else branch here and there we square 4 (as value of 'a' in this execution of 'product') to get 16 and multiply it with 'product(f)(5, 4)'.
Here, 'a' is greater than 'b', so we end 'product' with value 1.
As we propagate that back, we get 1 * 16 * 9 which, in turn equals 144.

Related

Is this scala function using right-fold or left-fold?

def calculate(f: Int => Int, sumProd:(Int, Int)=>Int, n: Int, a:Int, b:Int):Int =
if (a>b) n
else sumProd(f(a), calculate(f, sumProd, n, a+1, b))
This scala function can in a chosen number area (a to b) do chosen calculations with them:
example calling:
calculate(x=>2*x, (x,y)=>x+y, 0, 2 , 4)
this calculates: 2*2 + 2*3 + 2*4 = 18
Which folding(right- or left folding) is this function using? And how to see that?
further example callings for the function:
calculate(x=>2+x, (x,y)=>x*y,1, 2 , 4)
calculate(x=>2+x, (a,b)=>a+b,0, 1, 5)
calculate(x=>2*x, (a,b)=>a+b,0, 1, 5)
What you have is equivalent to, in pseudocode,
calculate(f, sumProd, n, a, b)
=
fold-right( sumProd, n, map(f, [a .. b]))
where [a .. b] denotes a list of numbers from a to b, inclusive, increasing by the step of 1. In other words, it is the same as
=
sumProd( f(a),
sumProd( f(a2),
sumProd( f(a3),
...
sumProd( f(b), n) ... )))

return a list of numbers in scala for which a predicate holds

I want to write a function in scala calcMod(a, b, c) where a should serve as a predicate and b and c taking the range of numbers (e.g. 3(incl.)...9(excl.)) which have to be evaluated and return a list of numbers in this range for which the predicate holds.
For example the function-call calcMod(k => k % 2 == 0, 3, 9) should evaluate in Return(4, 6, 8)
The fact that I have mod 2 == 0 makes it clear that even numbers will always be returned. I want to solve this with linear recursion.
def calcMod(a: Int => Boolean, b: Int, c: Int): List[Int] = ?
Below function will go from b until c, then apply filter with the function we got in argument.
def calcMod(a: Int => Boolean, b: Int, c: Int): List[Int] = (b until c filter a).toList

Explain some code which uses recursion and currying

How is the method product used in this code ?
The result for this function is 3600
So product takes a function : f ,
f takes an Int parameter which returns an Int parameter.
But does (a: Int, b: Int) not indicate that a function which takes two Int parameters are returned ?
I'm confused as to what is is occuring in this line :
f(a) * product(f)(a + 1, b)
Complete function :
def product(f: Int => Int)(a: Int, b: Int): Int =
if(a > b) 1
else {
f(a) * product(f)(a + 1, b)
}
product(x => x * x)(3 , 5)
In Scala, methods can have multiple parameter lists. In this example, the method product has two parameter lists: (f: Int => Int) and (a: Int, b: Int).
The first parameter list contains one parameter named f, which is of type Int => Int (a function that takes an Int and returns an Int).
The second parameter list contains two parameters named a and b which are both of type Int.
The expressions product(f)(a + 1, b) and product(x => x * x)(3 , 5) simply call the method with all three parameters.
The advantage of this is that you can "call" product with only the first parameter list. What you'll then get is a function that you can call by supplying the second parameter list. For example:
val fn = product(x => x * x) // only the first parameter list is applied
fn(3, 5) // fn is a function which you can pass the second list
"Calling" product with only the first parameter list is called currying.

Why converting '1' char to int using toInt method results to 49?

I want to convert a char to an int value.
I am a bit puzzled by the way toInt works.
println(("123").toList) //List(1, 2, 3)
("123").toList.head // res0: Char = 1
("123").toList.head.toInt // res1: Int = 49 WTF??????
49 pops up randomly for no reason.
How do you convert a char to int the right way?
For simple digit to int conversions there is asDigit:
scala> "123" map (_.asDigit)
res5: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 3)
Use Integer.parseInt("1", 10). Note that the 10 here is the radix.
val x = "1234"
val y = x.slice(0,1)
val z = Integer.parseInt(y)
val z2 = y.toInt //equivalent to the line above, see #Rogach answer
val z3 = Integer.parseInt(y, 8) //This would give you the representation in base 8 (radix of 8)
49 does not pop up randomly. It's the ascii representation of "1". See http://www.asciitable.com/
.toInt will give you the ascii value. It's probably easiest to write
"123".head - '0'
If you want to handle non-numeric characters, you can do
c match {
case c if '0' <= c && c <= '9' => Some(c - '0')
case _ => None
}
You can also use
"123".head.toString.toInt

Difference between fold and foldLeft or foldRight?

NOTE: I am on Scala 2.8—can that be a problem?
Why can't I use the fold function the same way as foldLeft or foldRight?
In the Set scaladoc it says that:
The result of folding may only be a supertype of this parallel collection's type parameter T.
But I see no type parameter T in the function signature:
def fold [A1 >: A] (z: A1)(op: (A1, A1) ⇒ A1): A1
What is the difference between the foldLeft-Right and fold, and how do I use the latter?
EDIT: For example how would I write a fold to add all elements in a list? With foldLeft it would be:
val foo = List(1, 2, 3)
foo.foldLeft(0)(_ + _)
// now try fold:
foo.fold(0)(_ + _)
>:7: error: value fold is not a member of List[Int]
foo.fold(0)(_ + _)
^
Short answer:
foldRight associates to the right. I.e. elements will be accumulated in right-to-left order:
List(a,b,c).foldRight(z)(f) = f(a, f(b, f(c, z)))
foldLeft associates to the left. I.e. an accumulator will be initialized and elements will be added to the accumulator in left-to-right order:
List(a,b,c).foldLeft(z)(f) = f(f(f(z, a), b), c)
fold is associative in that the order in which the elements are added together is not defined. I.e. the arguments to fold form a monoid.
fold, contrary to foldRight and foldLeft, does not offer any guarantee about the order in which the elements of the collection will be processed. You'll probably want to use fold, with its more constrained signature, with parallel collections, where the lack of guaranteed processing order helps the parallel collection implements folding in a parallel way. The reason for changing the signature is similar: with the additional constraints, it's easier to make a parallel fold.
You're right about the old version of Scala being a problem. If you look at the scaladoc page for Scala 2.8.1, you'll see no fold defined there (which is consistent with your error message). Apparently, fold was introduced in Scala 2.9.
For your particular example you would code it the same way you would with foldLeft.
val ns = List(1, 2, 3, 4)
val s0 = ns.foldLeft (0) (_+_) //10
val s1 = ns.fold (0) (_+_) //10
assert(s0 == s1)
Agree with other answers. thought of giving a simple illustrative example:
object MyClass {
def main(args: Array[String]) {
val numbers = List(5, 4, 8, 6, 2)
val a = numbers.fold(0) { (z, i) =>
{
println("fold val1 " + z +" val2 " + i)
z + i
}
}
println(a)
val b = numbers.foldLeft(0) { (z, i) =>
println("foldleft val1 " + z +" val2 " + i)
z + i
}
println(b)
val c = numbers.foldRight(0) { (z, i) =>
println("fold right val1 " + z +" val2 " + i)
z + i
}
println(c)
}
}
Result is self explanatory :
fold val1 0 val2 5
fold val1 5 val2 4
fold val1 9 val2 8
fold val1 17 val2 6
fold val1 23 val2 2
25
foldleft val1 0 val2 5
foldleft val1 5 val2 4
foldleft val1 9 val2 8
foldleft val1 17 val2 6
foldleft val1 23 val2 2
25
fold right val1 2 val2 0
fold right val1 6 val2 2
fold right val1 8 val2 8
fold right val1 4 val2 16
fold right val1 5 val2 20
25
There is two way to solve problems, iterative and recursive. Let's understand by a simple example.let's write a function to sum till the given number.
For example if I give input as 5, I should get 15 as output, as mentioned below.
Input: 5
Output: (1+2+3+4+5) = 15
Iterative Solution.
iterate through 1 to 5 and sum each element.
def sumNumber(num: Int): Long = {
var sum=0
for(i <- 1 to num){
sum+=i
}
sum
}
Recursive Solution
break down the bigger problem into smaller problems and solve them.
def sumNumberRec(num:Int, sum:Int=0): Long = {
if(num == 0){
sum
}else{
val newNum = num - 1
val newSum = sum + num
sumNumberRec(newNum, newSum)
}
}
FoldLeft: is a iterative solution
FoldRight: is a recursive solution
I am not sure if they have memoization to improve the complexity.
And so, if you run the foldRight and FoldLeft on the small list, both will give you a result with similar performance.
However, if you will try to run a FoldRight on Long List it might throw a StackOverFlow error (depends on your memory)
Check the following screenshot, where foldLeft ran without error, however foldRight on same list gave OutofMemmory Error.
fold() does parallel processing so does not guarantee the processing order.
where as foldLeft and foldRight process the items in sequentially for left to right (in case of foldLeft) or right to left (in case of foldRight)
Examples of sum the list -
val numList = List(1, 2, 3, 4, 5)
val r1 = numList.par.fold(0)((acc, value) => {
println("adding accumulator=" + acc + ", value=" + value + " => " + (acc + value))
acc + value
})
println("fold(): " + r1)
println("#######################")
/*
* You can see from the output that,
* fold process the elements of parallel collection in parallel
* So it is parallel not linear operation.
*
* adding accumulator=0, value=4 => 4
* adding accumulator=0, value=3 => 3
* adding accumulator=0, value=1 => 1
* adding accumulator=0, value=5 => 5
* adding accumulator=4, value=5 => 9
* adding accumulator=0, value=2 => 2
* adding accumulator=3, value=9 => 12
* adding accumulator=1, value=2 => 3
* adding accumulator=3, value=12 => 15
* fold(): 15
*/
val r2 = numList.par.foldLeft(0)((acc, value) => {
println("adding accumulator=" + acc + ", value=" + value + " => " + (acc + value))
acc + value
})
println("foldLeft(): " + r2)
println("#######################")
/*
* You can see that foldLeft
* picks elements from left to right.
* It means foldLeft does sequence operation
*
* adding accumulator=0, value=1 => 1
* adding accumulator=1, value=2 => 3
* adding accumulator=3, value=3 => 6
* adding accumulator=6, value=4 => 10
* adding accumulator=10, value=5 => 15
* foldLeft(): 15
* #######################
*/
// --> Note in foldRight second arguments is accumulated one.
val r3 = numList.par.foldRight(0)((value, acc) => {
println("adding value=" + value + ", acc=" + acc + " => " + (value + acc))
acc + value
})
println("foldRight(): " + r3)
println("#######################")
/*
* You can see that foldRight
* picks elements from right to left.
* It means foldRight does sequence operation.
*
* adding value=5, acc=0 => 5
* adding value=4, acc=5 => 9
* adding value=3, acc=9 => 12
* adding value=2, acc=12 => 14
* adding value=1, acc=14 => 15
* foldRight(): 15
* #######################
*/