I'm following a Coursera course for functional programming in Scala so that I can learn the language.
They introduced the concept of tail-recursive functions and defined them basically as a function that ends in a call to itself. But then they show this as the worked example:
def sum(f: Int => Int)(a: Int, b: Int): Int = {
def loop(a: Int, acc: Int): Int = {
if (a > b) acc
else loop(a + 1, f(a) + acc)
}
loop(a, 0)
}
If I annotate sum with #tailrec, I get an error because the IDE (IntelliJ) does not consider it to be tail recursive.
Is sum called tail-recursive here, or is the inner implementation "loop" the thing that is considered to be tail recursive in this case?
You're right. sum needs to call itself otherwise Scala will complain with:
#tailrec annotated method contains no recursive calls
If you tell compiler where exactly it is, by moving the #tailrec to where the tail recursion is:
def sum(f: Int => Int)(a: Int, b: Int): Int = {
#tailrec def loop(a: Int, acc: Int): Int = {
if (a > b) acc
else loop(a + 1, f(a) + acc)
}
loop(a, 0)
}
Then the compiler'll be satisfied it is tail-recursion optimised.
The inner loop method is tail-recursive, the sum method is not recursive at all. Therefore, you should annotate loop with #tailrec.
Moving loop to the outer scope may help visualize what's going on:
def sum(f: Int => Int)(a: Int, b: Int): Int = {
loop(a, 0)
}
def loop(a: Int, acc: Int): Int = {
if (a > b) acc
else loop(a + 1, f(a) + acc)
}
As you can see, sum is merely a public entry point for loop.
(Note that the code above won't compile because loop does not close over b or f anymore, but you get the point.)
Related
While doing Scala exercise I encountered this compilation problem by mistake which got me curious.
This is my FoldLeft implementation :
#annotation.tailrec
def foldLeft[A, B](l: List[A], b: B)(f:(B, A) => B): B = l match {
case Nil => b
case Cons(head, tail) => foldLeft(tail, f(b, head)) (f)
}
Using this FoldLeft I am creating sum function.
def sum1(l: List[Int]): Int = foldLeft(l, 0) (_ + _)
def sum2[A](l: List[Int]): Int = foldLeft(l, 0) (_ + _)
def sum3[Int](l: List[Int]): Int = foldLeft(l, 0) (_ + _)
sum1 and sum2 compiles and runs fine, however sum3 which looks similar to sum2 (used Int instead of A) does not compile saying "Can not resolve reference + signature".
In sum3, all Ints in the signature are the type parameter, not the scala.Int type. That is, sum3 is the same as
def sum4[A](l: List[A]): A = foldLeft(l, 0) (_ + _)
In sum2, the type parameter is pointless because it isn't used anywhere. The compiler will probably nearly always infer it as Nothing.
I'm trying to write a tail recursive function in the below way, but the compiler is throwing an error:
Too many arguments for method apply: (v1: Int)Int in trait Function1
else factorial(x-1, x*acc)
I had tried replacing Function1 with Function2 and gave Function2[Int, Int, Int] = new Function2[Int, Int, Int]
But it still threw me the same error. Can someone point out where i'm going wrong?
import scala.annotation.tailrec
var factorial: Function1[Int, Int] = new Function1[Int, Int] {
#tailrec override def apply (x:Int, acc:Int=1): Int = {
if (x<=1) acc
else factorial(x-1, x*acc)
}
}
factorial(5)
You apply inside Function1 must take only one param, when you are passing two.
You can rewrite it as follows:
var factorial: Function1[Int, Int] = new Function1[Int, Int] {
def apply (x:Int): Int = {
#tailrec def loop(x: Int, acc: Int = 1): Int = {
if (x<=1) acc
else loop(x-1, x*acc)
}
loop(x)
}
}
Function1 represents a function with a single parameter (the second one is for the output)
So you need to define your apply method with a single parameter, and then, inside it, do the recursion using a nested function:
import scala.annotation.tailrec
var factorial: Function1[Int, Int] = new Function1[Int, Int] {
override def apply(x: Int): Int = {
#tailrec
def go (x: Int, acc: Int = 1) : Int = {
if (x<=1) acc
else go(x-1, x*acc)
}
go(x)
}
}
factorial(5)
You can see this answer which is a great explanation of your issue. Your problem is you are trying to define apply as tail-recursive but you are not calling itself in the recursive call, you are calling factorial instead.
First off, you should use Function2 as your type for apply likewise:
import scala.annotation.tailrec
import scala.annotation.tailrec
var factorial: Function2[Int, Int, Int] = new Function2[Int, Int, Int] {
#tailrec override def apply (x:Int, acc:Int=1): Int = {
if (x<=1) acc
else apply(x-1, x * acc)
}
}
And then, if you get the error could not optimize #tailrec annotated method apply: it contains a recursive call targeting a supertype, you should call apply recursively as for a function to be tail recursive it always should be called exactly itself as the last statement.
scala> factorial(5, 1)
res3: Int = 120
Function2 take 3 type parameters. Last one is the output type.
Scala REPL
scala> :paste
// Entering paste mode (ctrl-D to finish)
val fac: Function2[Int, Int, Int] = new Function2[Int, Int, Int] {
def apply(v1: Int, v2: Int): Int = if (v1 == 1) v2 else apply(v1 - 1, v1 * v2)
}
// Exiting paste mode, now interpreting.
fac: (Int, Int) => Int = <function2>
scala> fac(5, 1)
res1: Int = 120
You can syntactic sugar (function syntax in scala using =>) instead of using interface/trait Function2.
scala> :paste
// Entering paste mode (ctrl-D to finish)
val fac: (Int, Int) => Int = (acc, c) => if (c == 1) acc else fac(acc * c, c - 1)
// Exiting paste mode, now interpreting.
fac: (Int, Int) => Int = $$Lambda$1092/1204822967#5c83ae01
scala> fac(1, 5)
res0: Int = 120
Or, if you like some syntactic sugar, you can write it:
val f: (Int) => BigInt = (x) => {
if (x <= 1) 1
else x * f(x - 1)
}
println(f(30))
Or true tail-recursive function:
val f: (Int) => BigInt = (x) => {
#tailrec
def helper(x: Int, acc: BigInt = 1): BigInt = {
if (x <= 1) acc
else helper(x - 1, x * acc)
}
helper(x)
}
println(f(30))
The syntax of currying in scala is for example
def f(x: Int, b: Int) = x + y
is
def f(x: Int)(b: Int) = x + y
And currying for sum to sum for given range a and b is
def sum(f: Int => Int, a: Int, b: Int) = {
...
}
sum(x=>x, 3, 6) // outcome is 18 (3+4+5+6)
is
def sum(f: Int => Int): (Int, Int) => Int = {
def sumF(a: Int, b: Int): Int =
if (a > b) 0
else f(a) + sumF(a + 1, b)
sumF
}
sum(x=>x)(3, 6) // outcome is 18 (3+4+5+6)
But I don't understand why colon(:)
exists between (f: Int => Int) and (Int, Int)
in def sum(f: Int => Int): (Int, Int) => Int = {
instead of
def sum(f: Int => Int)(Int, Int) => Int = {
Your sum example is not curried. If you wanted it curried you'd do something like:
def sum(f: Int => Int)(a: Int, b: Int): Int =
if (a > b) 0
else f(a) + sum(f)(a + 1, b)
sum(x=>x)(3, 6) // res0: Int = 18
Your code defines a method that takes a single argument, def sum(f: Int => Int). That argument is a function that takes and Int and returns an Int. So no currying involved.
This sum method returns a function, : (Int, Int) => Int. This returned function takes 2 Ints and returns and Int. Invoking this sum method looks like currying, but it's not.
sum(x=>x)(3, 6)
Instead you are invoking sum() with a single argument (x=>x) and then invoking the returned function with two arguments (3,6).
(Int, Int) => Int between : and = specify the function's return type, i.e, it says sum will return another method of signature (Int, Int) => Int which takes two Int and returns another Int, and this is the signature of your inner sumF function:
You can rewrite this to the currying syntax as follows:
def sum(f: Int => Int)(a: Int, b: Int): Int = {
def sumF(a: Int, b: Int): Int =
if (a > b) 0
else f(a) + sumF(a + 1, b)
sumF(a, b)
}
This will more or less do the same thing as the method defined in OP:
sum(x => x)(3, 6)
// res11: Int = 18
But these two definitions are not exactly the same, for instance, for the currying syntax defined here, if you want to generate a new method from it, you have to specify the variable type, like:
val mysum: (Int, Int)=> Int = sum(x => x)
But for the one in OP, it can be simply val mysum = sum(x => x) as the return type of sum as already been specified.
The following two higher-order functions yield the same result, but I'm having trouble understanding the difference between the two. In fact, I don't understand 1). How can a function have two sets of ()?
1)
def sum(f: Int => Int) (a: Int, b: Int) = {
def loop(a: Int, acc: Int) : Int =
if (a > b) acc
else loop (a + 1, f(a) + acc)
loop (a, 0)
}
2)
def sum(f: Int => Int, a: Int, b: Int) = {
def loop(a: Int, acc: Int) : Int =
if (a > b) acc
else loop (a + 1, f(a) + acc)
loop (a, 0)
}
The first function is curried. Meaning you can partially apply it more easily. If you only use the first parameter list the function returns another function with the signature (Int, Int) => Int.
This is really useful if you need to pass a function with a specific function signature to higher order functions like map or reduce.
In other functional programming languages like Haskell, all functions are curried by default.
I wrote a whole blog post on this topic in case you're interested. You can read it right here.
I have this code:
for( i <- 0 to 8){
((numbers(i) - i)/3).abs + ((numbers(i) - i)%3).abs
}
and I would like to do, as the title says, something like this
for( i <- 0 to 8){
by3(numbers(i), i, /) + by3(numbers(i), i, %)
}
def by3(a: Int, b: Int, op: Int => Int) = ((a - b) op 3).abs
and probably also use a partially applied function for it.. but by now this would be possible to achieve? How?
First, you need to correctly define op as a function (specifically, a Function2)
def operate(a: Int, b: Int, op: (Int, Int) => Int ) : Int = (op ((a - b), 3)).abs
Operators in Scala are actually methods: + is a method of Int(and Long, Double, ...) in Scala OO foundation. Then, to pass a operator (method) as a function, you can lift it using the underscore notation:
operate(5, 3, _ + _)
To get rid of the underscores you need to define the functions as values.
val / = (a:Int, b: Int) => a / b
val % = (a:Int, b: Int) => a % b
def by3(a: Int, b: Int, fn: (Int, Int) => Int): Int = fn(a - b, 3).abs
(0 to 8).foreach(i => by3(numbers(i), i, /) + by3(numbers(i), i, %))
Edited/Update:
Being concise, the shortest way to do it is:
def doStuff(a: Int, b: Int, op: (Int, Int) => Int) = {op(a - b, 3).abs}
doStuff(4,1,_%_)
So you can doStuff(numbers(i), i, _ / _) + doStuff(numbers(i), i, _ % _)