Currying: can't understand this example

In this example, taken directly from my study materials, I can’t understand how sumF can determine that f is cube . sum takes cube as argument, but returns sumF: then, what happens to cube?
I try to follow the execution, but I think I’m missing something and I don’t know what.
Maybe is something related to scope; I thought: if sum function return sumF function this means that sum doesn’t really terminate until sumF is running or until it is just indicated and not calculated (and the same with any other embedded functions). Like in math when we use a result indicated rather than calculated.

Am I wrong?

So the thing is, in Scala functions are values, just like any other value – you can pass them as parameters, assign them to val, and so on.

sum() is taking one function (cube) as parameter f, building a new function out of that, and returning that as its result. It’s not that it doesn’t terminate – it’s that it is returning a new function that you can then use. The value of f is captured in what we call a “closure”, and can be used in the returned function.

So sumCubes() is calling sum() and getting back a new function, which is a sum of cubes. And then in line 13, you are calling sumCubes() to get the final result.

1 Like

Oh ok, now it is 90% clear.
I studied everything you mentioned except closure: I didn’t find this in the study text (a bit strange then) until now and it confused me because I didn’t understand how sumF() could retrieve f (cube in this case).

So now I have to dedicate myself to studying closures.

Thank you

Hello, and welcome to the community.

First of all, for futures questions, it would be better to put code (as text) rather than images.

Second, I believe that the core concept you are missing here are functions.
Scala, has functions as first class citizens. That means that functions are values, you can assign them to values, pass them as arguments, and return them and have methods associated to them.

So let’s try to understand what is happening.

def sum(f: Int => Int): (Int,  Int) => Int

So we have a method sum which receives a function from an Int to an Int, and returns another function from two Ints into an Int.

Now, as you can see, what the sum method does is creates another method sumF and return it (the compiler can implicitly transform methods into functions when the last is required).
So let’s see the body of sumF

def sumF(a: Int, b: Int): Int =
  if (a > b) 0  else f(a) + sumF(a + 1, b)

So we got a method that receives two Ints and returns an Int.
And the body is quite simple, if a is greater than b then returns zero, otherwise return the sum of f(a) with sumF(a + 1, b). And what is f is the function that was passed to sum.

So calling sum(square) just returns a function (sumF) it haven’t executed anything (more over, you could assign that to a val, instead of a def). And when you call sumCubes(2, 3) what happens if the following.

sumCubes(2, 3)
if (2 > 3) 0 else f(2) + sumF(2 + 1, 3) // By definition of sumF.
f(2) + sumF(2 + 1, 3) // By evaluation of if.
(2 * 2 * 2) + sumF(2 + 1, 3) // By definition of cube.
8 + sumF(2 + 1, 3) // By evaluation of *.
8 + (if (3 > 3) 0 else f(3) + sumF(3 + 1, 3)) // By definition of sumF.
8 + (f(3) + sumF(3 + 1, 3)) // By evaluation of if.
8 + ((3 * 3 * 3) + sumF(3 + 1, 3)) // By definition of cube.
8 + 27 + sumF(3 + 1, 3) // By evaluation of *.
8 + 27 + (if (4 > 3) 0 else f(4) + sumF(4 + 1, 3)) // By definition of sumF.
8 + 27 + 0 // By evaluation of if.
35 // By evaluation of +.
3 Likes

Hello, thank you.

  1. Clear, as text :slightly_smiling_face:

  2. I really needed a step by step illustration, very useful and clear, thanks!
    Actually I have already studied the concept of functions as first class citizens, the possibility to return functions, etc.
    But the main void was about evaluation of f: how sumF can evaluate f correctly if f is binded to sum and sum ended returning sumF. Your answer plus jducoeur’s are useful.
    So, focusing only on “evaluation of f”, is it all about scope and closure?

1 Like

Yeah so while closures are a more complex topic than what I am about to say (and I have to admit I do not know too much on how they work under the hood, but you also shouldn’t need to).

But the basic understanding of those is that they capture the values on their scope that are used inside the function body.

So when in sumF you refer to f and then you transform that method into a function, the compiler saves the reference of f that was passed into sum in the body of the newly generated object.

1 Like

Oh clear! The last phrase in particular, very useful!

Thank you.

The scope/closure aspect in your example is mostly f being accessible from within sumF without ever having been introduced to its direct scope. In principle you could add f as a dedicated parameter to sumF to make this more explicit (but also more verbose without actual gain):

def sum2(f: Int => Int): (Int, Int) => Int = {
  def sumF(ff: Int => Int)(a: Int, b: Int): Int =
    if(a > b) 0 else ff(a) + sumF(ff)(a + 1, b)
  sumF(f)
}

Note that with this change, the application of sumF incidentally becomes a better example of currying, IMHO, since currying usually is introduced as “converting a function that takes multiple arguments into a sequence of functions that each take a single argument” (see e.g. Wikipedia). Here the single argument is the function (f/ff), and the remaining, unapplied part is just a function (Int, Int) => Int.

2 Likes