I want to understand how without defining the function variables methods still work. Code in case:
@ class Box(var x: Int) {
def update(f: Int => Int) = x = f(x)
def printMsg(msg: String) = {
println(msg x)
Now, if I perform the following calls, I get the desired output:
val b = new Box(1)
b.printMsg("Hello")
Hello1
b.update(i => i 5)
b.printMsg("Hello")
Hello6
In the update
's definition, I do not tell it what to do. I just tell that assign the object's x
property the result of f(x)
. But what f(x)
does is not defined anywhere.
However, when I call the update()
function, I pass on a function value: i => i 5
. Does this mean that every time I call update
, I define the function and keep in mind that this new function should take and return an Int
?
I also read How Higher Order functions work in Scala post on Stackoverflow and I am not sure whether I got it right:
The function:
def higher_order(a:Int,b:Int,c:Int,f:(Int,Int)=>Int):Int=f(f(a,b),c)
takes 3 integers and one functional value which furthermore takes two integers and return one integer. The function f
is not defined anywhere, however, the function higher_order
is defined as: take 3 integers, take one functional value, return an integer and perform: f(f(a,b),c)
.
The OP calls this function as: higher_order(1,2,3,_ _)
and gets the result as 6.
The OP defines _ _
as the last argument in place of the function value parameter. So, is my thought process of defining the function value upon calling and ensuring that the args and return type matches is valid?
CodePudding user response:
Does this mean that every time I call update, I define the function
No, not necessarily. The update
method takes a function as a parameter:
def update(f: Int => Int) = x = f(x)
When update
is called, a function must be passed to it. One way is to define a lambda function where the function is called:
box.update(i => i 5)
This lambda function is created by the compiler once and then passed to update
every time this code is called. Using a lambda function avoids the need to name the function and makes the code simpler and cleaner. (In this case it could even be update(_ 5)
which is short but easily understood once you get to know Scala)
If you call update
the same way in another part of the code, a second lambda function is created and passed to update
.
box1.update(i => i 5) // First lambda function instance
box2.update(i => i 5) // This is a different function instance
But the function can also be defined once in advance and passed to update
:
def add5(i: Int) = i 5
box.update(add5)
In this case the definition of add5
is independent of the call to update
. And add5
is a single function that can be used multiple times which, in some cases, may be clearer:
box1.udpate(add5)
box2.update(add5)
box3.update(add5)
In both cases the type of f
must be compatible with Int => Int
. In the case of a lambda function, the compiler knows what type is expected and applies the appropriate types to the arguments if they are not provided. Thus when you pass i => i 5
to Int => Int
, the compiler set the type of i
to Int
because that is what Int => Int
expects. For the stand-alone add5
function the type of i
must be supplied explicitly because the compiler doesn't know how this function is going to be used.
To break down the more complex high-order functions, just remember that functions are types like any other. They can be nested inside each other, used as arguments to other functions, and used to parameterise standard containers like List
(e.g. List[Int => Int]
)