scala. higher order function calling by name. does

2020-06-07 05:09发布

问题:

Just want to clarify. If we use higher-order function (f. that accepts another function as argument). Does it make any sense specify "=>" sign to call it by-name. It seems arg-function is calling by-name anyhow?

There is an example:

// 1.
  // the function that accepts arg-function with: two int params and returning String
  // the function passing v1 & v2 as parameters to arg-function, invoking arg-function 2 times, connecting the result to one string
  def takeFunction1(f: (Int, Int) => String, v1:Int, v2:Int ): String = {
     f(v1, v2) + f(v1, v2)
  }

  // 2. same as #1 but calling arg-function by-name
  def takeFunction2(f: => ((Int, Int) => String), v1:Int, v2:Int ): String = {
    f(v1, v2) + f(v1, v2)
  }    

  def aFun(v1:Int, v2:Int) : String = {
    (v1 + v2).toString
  }

  // --

 println( takeFunction1( aFun, 2, 2) )

 println( takeFunction2( aFun, 2, 2) )

And what if I want to call it like this ?:

println( takeFunction2( aFun(2,2)), ... ) // it tries to evaluate immediately when passing

回答1:

The difference is that if you pass as the first argument a call to a function that returns the (Int, Int) => String value to use, this call to the generator function is evaluated only once with pass-by-value, compared to being evaluated each time the argument is used in the case of pass-by-name.

Rather contrived example:

var bar = 0

def fnGen() = {
  bar += 1
  def myFun(v1:Int, v2:Int) = {
    (v1 + v2).toString
  }
  myFun _
}

Now run some calls of your methods above using fnGen:

scala> println( takeFunction1( fnGen(), 2, 2) )
44

scala> bar
res1: Int = 1

scala> println( takeFunction2( fnGen(), 2, 2) )
44

scala> bar
res3: Int = 3

As you can see, calling takeFunction1 increments bar only once, while calling takeFunction2 increments bar twice.



回答2:

The argument that you're passing by name is aFun; that's a valid expression, and it does get evaluated both times that takeFunction2 uses it, but since it's just a variable, and you're not doing anything else with it, "evaluating" it is not very meaningful. (It just evaluates to the same value both times.) For pass-by-name to behave differently from pass-by-value, you have to pass in an impure expression (one that has side-effects, or that can evaluate to different values on successive calls, or whatnot).



标签: scala