Reputation: 4500
Here's my failed attempt at doing what I'd like to do:
var currentNum = 0
def adder = (x:Int, y:Int) => x+y
def getNumAdder = {x: Int =>
val currentNumSnapshot = currentNum
adder(x, currentNumSnapshot)
}
currentNum = 5
val addFive = getNumAdder
currentNum = 9
val addNine = getNumAdder
println("10 plus 5 is "+addFive(10))
println("10 plus 9 is "+addNine(10))
":paste" that in the Scala REPL and you'll get this:
10 plus 5 is 19
10 plus 9 is 19
I want to be able to call getNumAdder and get a function that adds a snapshot of the current value to an inputted number. What can I change to get the desired behavior?
UPDATE:
As per the warnings promoting referential transparency, I believe this code, a simple example of currying in Scala, does what I need as well.
var currentNum = 0
def adder(x:Int) = (y:Int) => x+y
def getNumAdder(input: Int) = {
adder(input)
}
currentNum = 5
val addFive = getNumAdder(currentNum)
Upvotes: 0
Views: 94
Reputation: 170713
def getNumAdder = {
val currentNumSnapshot = currentNum
adder((_: Int), currentNumSnapshot) // or (x: Int) => adder(x, currentNumSnapshot)
}
Note that it has to be a def
, not a val
, so that currentNumSnapshot
is evaluated every time getNumAdder
is called.
Note that
{x: Int =>
val currentNumSnapshot = currentNum
adder(x, currentNumSnapshot)
}
is quite different from
{
val currentNumSnapshot = currentNum
(x: Int) => adder(x, currentNumSnapshot)
}
In my version when getNumAdder
is evaluated, I first save the current value of currentNum
and then return the function which uses this snapshot. In your version the entire block is the function which is returned, so the line val currentNumSnapshot = currentNum
is only executed when the function is called (e.g. addFive(10)
) and so obviously uses the value of currentNum
at that time.
And as goral notes, it's usually a bad idea to do something like that in real code, I am assuming this is only done for understanding.
Upvotes: 2
Reputation: 5426
The problem is that you are capturing the value of currentNum
when the function is called and not when it is created. Sou you must change it to:
var currentNum = 0
def adder = (x:Int, y:Int) => x + y
def getNumAdder = {
val currentNumSnapshot = currentNum
x: Int => adder(x, currentNumSnapshot)
}
currentNum = 5
val addFive = getNumAdder
currentNum = 9
val addNine = getNumAdder
This will work as expected:
scala> println("10 plus 5 is "+addFive(10))
10 plus 5 is 15
scala> println("10 plus 9 is "+addNine(10))
10 plus 9 is 19
Upvotes: 0
Reputation: 1265
I don't know if this one satisfy you but it's working:
var currentNum = 0 //> currentNum : Int = 0
def adder = (x: Int, y: Int) => x + y //> adder: => (Int, Int) => Int
val getNumAdder = { x: Int =>
val currentNumSnapshot = currentNum
println(currentNumSnapshot)
adder(x, currentNumSnapshot) //> getNumAdder : Int => Int = <function1>
}
def curriedAdder = adder.curried //> curriedAdder: => Int => (Int => Int)
currentNum = 5
val addFive = curriedAdder(currentNum) //> addFive : Int => Int = <function1>
currentNum = 9
val addNine = curriedAdder(currentNum) //> addNine : Int => Int = <function1>
println("10 plus 5 is " + addFive(10)) //> 10 plus 5 is 15
println("10 plus 9 is "+addNine(10)) //> 10 plus 9 is 19
Upvotes: 0