在Scala中调用名称vs调用,需要澄清。

时间:2023-02-04 23:13:07

As I understand it, in Scala, a function may be called either

按照我的理解,在Scala中,函数可以被调用

  • by-value or
  • 传递或
  • by-name
  • 的名字

For example, given the following declarations, do we know how the function will be called?

例如,给定以下声明,我们知道如何调用函数吗?

Declaration:

声明:

def  f (x:Int, y:Int) = x;

Call

调用

f (1,2)
f (23+55,5)
f (12+3, 44*11)

What are the rules please?

请问有什么规定?

16 个解决方案

#1


421  

The example you have given only uses call-by-value, so I will give a new, simpler, example that shows the difference.

您所给出的示例仅使用了调用的值,因此我将给出一个新的、更简单的示例,以显示不同之处。

First, let's assume we have a function with a side-effect. This function prints something out and then returns an Int.

首先,假设我们有一个具有副作用的函数。这个函数输出一些东西,然后返回一个Int。

def something() = {
  println("calling something")
  1 // return value
}

Now we are going to define two function that accept Int arguments that are exactly the same except that one takes the argument in a call-by-value style (x: Int) and the other in a call-by-name style (x: => Int).

现在我们将定义两个接受Int参数的函数,它们是完全相同的,除了其中一个参数是按值调用样式(x: Int),另一个是按名称调用样式(x: => Int)。

def callByValue(x: Int) = {
  println("x1=" + x)
  println("x2=" + x)
}

def callByName(x: => Int) = {
  println("x1=" + x)
  println("x2=" + x)
}

Now what happens when we call them with our side-effecting function?

当我们用副作用函数调用它们时会发生什么呢?

scala> callByValue(something())
calling something
x1=1
x2=1

scala> callByName(something())
calling something
x1=1
calling something
x2=1

So you can see that in the call-by-value version, the side-effect of the passed-in function call (something()) only happened once. However, in the call-by-name version, the side-effect happened twice.

因此,您可以看到,在按值的版本中,传入函数调用的副作用(某些())只发生一次。然而,在按名字调用的版本中,副作用发生了两次。

This is because call-by-value functions compute the passed-in expression's value before calling the function, thus the same value is accessed every time. However, call-by-name functions recompute the passed-in expression's value every time it is accessed.

这是因为按值调用函数在调用函数之前计算传入表达式的值,因此每次都访问相同的值。然而,在每次访问时,调用的名称函数都会重新计算传入表达式的值。

#2


43  

Here is an example from Martin Odersky:

这是Martin Odersky的一个例子:

def test (x:Int, y: Int)= x*x

We want to examine the evaluation strategy and determine which one is faster (less steps) in these conditions:

我们希望检查评估策略,并确定在这些条件下哪个是更快的(更少的步骤):

test (2,3)

call by value: test(2,3) -> 2*2 -> 4
call by name: test(2,3) -> 2*2 -> 4
Here the result is reached with the same number of steps.

按值调用:test(2,3) -> 2*2 -> 4按名称调用:test(2,3) -> 2*2 ->

test (3+4,8)

call by value: test (7,8) -> 7*7 -> 49
call by name: (3+4) (3+4) -> 7(3+4)-> 7*7 ->49
Here call by value is faster.

按值调用:test(7,8) -> 7*7 ->49按名称调用:(3+4)(3+4)-> 7(3+4)-> 7*7 ->49按值调用更快。

test (7,2*4)

call by value: test(7,8) -> 7*7 -> 49
call by name: 7 * 7 -> 49
Here call by name is faster

按值调用:test(7,8) -> 7*7 -> 49按名字调用:7*7 -> 49这里按名字调用更快

test (3+4, 2*4) 

call by value: test(7,2*4) -> test(7, 8) -> 7*7 -> 49
call by name: (3+4)(3+4) -> 7(3+4) -> 7*7 -> 49
The result is reached within the same steps.

调用值:test(7,2*4) -> test(7, 8) -> 7*7 -> 49调用名:(3+4)-> 7(3+4)-> 7*7 -> 49

#3


14  

In the case of your example all the parameters will be evaluated before it's called in the function , as you're only defining them by value. If you want to define your parameters by name you should pass a code block:

在示例中,所有参数将在函数中调用之前进行计算,因为您只是按值定义它们。如果您想按名称定义参数,您应该传递一个代码块:

def f(x: => Int, y:Int) = x

This way the parameter x will not be evaluated until it's called in the function.

这样,参数x在函数调用之前不会被计算。

This little post here explains this nicely too.

这里的这篇文章也很好地解释了这一点。

#4


7  

I will try to explain by a simple use case rather than by just providing an example

我将尝试用一个简单的用例来解释,而不是仅仅提供一个示例

Imagine you want to build a "nagger app" that will Nag you every time since time last you got nagged.

假设你想要构建一个“nagger应用程序”,它会在你上次被人骚扰之后每次都唠叨你。

Examine the following implementations:

检查以下的实现:

object main  {

    def main(args: Array[String]) {

        def onTime(time: Long) {
            while(time != time) println("Time to Nag!")
            println("no nags for you!")
        }

        def onRealtime(time: => Long) {
            while(time != time) println("Realtime Nagging executed!")
        }

        onTime(System.nanoTime())
        onRealtime(System.nanoTime())
    }
}

In the above implementation the nagger will work only when passing by name the reason is that, when passing by value it will re-used and therefore the value will not be re-evaluated while when passing by name the value will be re-evaluated every time the variables is accessed

在上面的实现中,nagger只在传递name时才会工作,原因是,当传递value时,它将被重用,因此当传递name时,该值将不会被重新评估,而每次访问变量时,该值将被重新评估

#5


6  

To iteratate @Ben's point in the above comments, I think it's best to think of "call-by-name" as just syntactic sugar. The parser just wraps the expressions in anonymous functions, so that they can be called at a later point, when they are used.

为了在上面的评论中重复@Ben的观点,我认为最好把“按名字叫”看成是语法上的糖。解析器只是将表达式封装在匿名函数中,以便在稍后使用表达式时调用它们。

In effect, instead of defining

实际上,不是定义

def callByName(x: => Int) = {
  println("x1=" + x)
  println("x2=" + x)
}

and running:

并运行:

scala> callByName(something())
calling something
x1=1
calling something
x2=1

You could also write:

你也可以写:

def callAlsoByName(x: () => Int) = {
  println("x1=" + x())
  println("x2=" + x())
}

And run it as follows for the same effect:

并按如下方式运行:

callAlsoByName(() => {something()})

calling something
x1=1
calling something
x2=1

#6


4  

Typically, parameters to functions are by-value parameters; that is, the value of the parameter is determined before it is passed to the function. But what if we need to write a function that accepts as a parameter an expression that we don't want evaluated until it's called within our function? For this circumstance, Scala offers call-by-name parameters.

通常,函数的参数是按值参数;也就是说,参数的值是在传递给函数之前确定的。但是,如果我们需要编写一个函数作为参数接受一个表达式,我们不希望它在函数中被调用之前被求值呢?对于这种情况,Scala提供按名称调用的参数。

A call-by-name mechanism passes a code block to the callee and each time the callee accesses the parameter, the code block is executed and the value is calculated.

按名称调用机制将代码块传递给被调用者,每次被调用者访问参数时,执行代码块并计算值。

object Test {
def main(args: Array[String]) {
    delayed(time());
}

def time() = {
  println("Getting time in nano seconds")
  System.nanoTime
}
def delayed( t: => Long ) = {
  println("In delayed method")
  println("Param: " + t)
  t
}
}
 1. C:/>scalac Test.scala 
 2. scala Test
 3. In delayed method
 4. Getting time in nano seconds
 5. Param: 81303808765843
 6. Getting time in nano seconds

#7


3  

As i assume, the call-by-value function as discuss above pass just the values to the function. According to Martin Odersky It is a Evaluation strategy follow by a Scala that play the important role in function evaluation. But, Make it simple to call-by-name. its like a pass the function as a argument to the method also know as Higher-Order-Functions. When the method access the value of passed parameter, it call the implementation of passed functions. as Below:

正如我所假设的,上面讨论的按值调用函数只将值传递给函数。根据Martin Odersky的观点,这是Scala之后的一种评估策略,在函数评估中扮演着重要的角色。但是,要简化按名字调用的过程。它就像把函数作为参数传递给方法,方法也称为高阶函数。当方法访问传递参数的值时,它调用传递函数的实现。如下:

According to @dhg example, create the method first as:

根据@dhg示例,首先创建方法为:

def something() = {
 println("calling something")
 1 // return value
}  

This function contain one println statement and return an integer value. Create the function, who have arguments as a call-by-name:

这个函数包含一个println语句并返回一个整数值。创建函数,其参数为按名称调用:

def callByName(x: => Int) = {
 println("x1=" + x)
 println("x2=" + x)
}

This function parameter, is define an anonymous function who have return one integer value. In this x contain an definition of function who have 0 passed arguments but return int value and our something function contain same signature. When we call the function, we pass the function as a argument to callByName. But in the case of call-by-value its only pass the integer value to the function. We call the function as below:

这个函数参数是定义一个匿名函数,它返回一个整数值。在这个x中包含一个函数的定义,该函数的参数为0,但返回int值,我们的某某函数包含相同的签名。当我们调用函数时,我们将函数作为参数传递给callByName。但是对于按值调用,它只将整数值传递给函数。我们将该函数称为:

scala> callByName(something())
 calling something
 x1=1
 calling something
 x2=1 

In this our something method called twice, because when we access the value of x in callByName method, its call to the defintion of something method.

在这个东西方法中,我们调用了两次,因为当我们在callByName方法中访问x的值时,它调用了一个方法的定义。

#8


2  

There are already lots of fantastic answers for this question in Internet. I will write a compilation of several explanations and examples I have gathered about the topic, just in case someone may find it helpful

互联网上已经有很多关于这个问题的奇妙答案了。我将把我收集到的关于这个主题的几个解释和例子汇编在一起,以防有人发现它有用

INTRODUCTION

介绍

call-by-value (CBV)

cb v值()都未

Typically, parameters to functions are call-by-value parameters; that is, the parameters are evaluated left to right to determine their value before the function itself is evaluated

通常,函数的参数是按值调用的参数;也就是说,在对函数本身进行求值之前,从左到右对参数进行求值

def first(a: Int, b: Int): Int = a
first(3 + 4, 5 + 6) // will be reduced to first(7, 5 + 6), then first(7, 11), and then 7

call-by-name (CBN)

call-by-name(CBN)

But what if we need to write a function that accepts as a parameter an expression that we don't to evaluate until it's called within our function? For this circumstance, Scala offers call-by-name parameters. Meaning the parameter is passed into the function as it is, and its valuation takes place after substitution

但是,如果我们需要编写一个函数,它接受一个参数,一个表达式,我们在函数中调用它之前不需要对它求值呢?对于这种情况,Scala提供按名称调用的参数。意思是把参数按原样传递到函数中,并在替换后进行赋值

def first1(a: Int, b: => Int): Int = a
first1(3 + 4, 5 + 6) // will be reduced to (3 + 4) and then to 7

A call-by-name mechanism passes a code block to the call and each time the call accesses the parameter, the code block is executed and the value is calculated. In the following example, delayed prints a message demonstrating that the method has been entered. Next, delayed prints a message with its value. Finally, delayed returns ‘t’:

按名称调用机制将代码块传递给调用,每次调用访问参数时,执行代码块并计算值。在下面的示例中,延迟打印一条消息,说明方法已经输入。接下来,delay打印一个带有其值的消息。最后,推迟返回“t”:

 object Demo {
       def main(args: Array[String]) {
            delayed(time());
       }
    def time() = {
          println("Getting time in nano seconds")
          System.nanoTime
       }
       def delayed( t: => Long ) = {
          println("In delayed method")
          println("Param: " + t)
       }
    }

In delayed method
Getting time in nano seconds
Param: 2027245119786400

在延迟方法中,以纳秒为单位获取时间:2027245119786400

PROS AND CONS FOR EACH CASE

每种情况的利弊

CBN: +Terminates more often * check below above termination * + Has the advantage that a function argument is not evaluated if the corresponding parameter is unused in the evaluation of the function body -It is slower, it creates more classes (meaning the program takes longer to load) and it consumes more memory.

CBN:+终止更多*检查以下终止* +以上的优点是函数参数不是评估如果相应的参数是未使用的评价函数体——是慢的,它创造了更多的类(即程序需要更长的时间来加载),它会消耗更多的内存。

CBV: + It is often exponentially more efficient than CBN, because it avoids this repeated recomputation of arguments expressions that call by name entails. It evaluates every function argument only once + It plays much nicer with imperative effects and side effects, because you tend to know much better when expressions will be evaluated. -It may lead to a loop during its parameters evaluation * check below above termination *

它通常比CBN效率更高,因为它避免了按名称调用的参数表达式的重复计算。它只对每个函数参数求值一次+它在执行效果和副作用方面表现得更好,因为当表达式被求值时,您往往知道得更好。-在其参数评估过程中可能导致循环*在上述终止项下检查*

What if termination is not guaranteed?

如果终止没有保证怎么办?

-If CBV evaluation of an expression e terminates, then CBN evaluation of e terminates too -The other direction is not true

-如果一个表达式e的CBV评价终止,那么CBN对e的评价也终止——另一个方向不成立

Non-termination example

Non-termination例子

def first(x:Int, y:Int)=x

Consider the expression first(1,loop)

首先考虑的表达式(循环)

CBN: first(1,loop) → 1 CBV: first(1,loop) → reduce arguments of this expression. Since one is a loop, it reduce arguments infinivly. It doesn’t terminate

CBN:首先cb v(1、循环)→1:都未前(1、循环)→减少参数的表达式。因为一个是循环,它减少了不定式的参数。它不会终止

DIFFERENCES IN EACH CASE BEHAVIOUR

每个案例行为的差异。

Let's define a method test that will be

让我们定义一个方法测试

Def test(x:Int, y:Int) = x * x  //for call-by-value
Def test(x: => Int, y: => Int) = x * x  //for call-by-name

Case1 test(2,3)

Case1测试(2、3)

test(2,3)   →  2*2 → 4

Since we start with already evaluated arguments it will be the same amount of steps for call-by-value and call-by-name

因为我们从已经计算过的参数开始,所以按值调用和按名称调用的步骤数量是相同的

Case2 test(3+4,8)

例2测试(3 + 4,8)

call-by-value: test(3+4,8) → test(7,8) → 7 * 7 → 49
call-by-name: (3+4)*(3+4) → 7 * (3+4) → 7 * 7 → 49

In this case call-by-value performs less steps

在这种情况下,按值执行更少的步骤。

Case3 test(7, 2*4)

Case3测试(7、2 * 4)

call-by-value: test(7, 2*4) → test(7,8) → 7 * 7 → 49
call-by-name: (7)*(7) → 49

We avoid the unnecessary computation of the second argument

我们避免不必要地计算第二个参数

Case4 test(3+4, 2*4)

Case4测试(3 + 4,2 * 4)

call-by-value: test(7, 2*4) → test(7,8) → 7 * 7 → 49
call-by-name: (3+4)*(3+4) → 7*(3+4) → 7*7 →  49

Different approach

不同的方法

First, let's assume we have a function with a side-effect. This function prints something out and then returns an Int.

首先,假设我们有一个具有副作用的函数。这个函数输出一些东西,然后返回一个Int。

def something() = {
  println("calling something")
  1 // return value
}

Now we are going to define two function that accept Int arguments that are exactly the same except that one takes the argument in a call-by-value style (x: Int) and the other in a call-by-name style (x: => Int).

现在,我们将定义两个函数,它们接受的是完全相同的Int参数,除了一个以调用-by-value样式(x: Int)和另一个以callby -by-name样式(x: => Int)进行参数转换。

def callByValue(x: Int) = {
  println("x1=" + x)
  println("x2=" + x)
}
def callByName(x: => Int) = {
  println("x1=" + x)
  println("x2=" + x)
}

Now what happens when we call them with our side-effecting function?

当我们用副作用函数调用它们时会发生什么呢?

scala> callByValue(something())
calling something
x1=1
x2=1
scala> callByName(something())
calling something
x1=1
calling something
x2=1

So you can see that in the call-by-value version, the side-effect of the passed-in function call (something()) only happened once. However, in the call-by-name version, the side-effect happened twice.

因此,您可以看到,在按值的版本中,传入函数调用的副作用(某些())只发生一次。然而,在按名字调用的版本中,副作用发生了两次。

This is because call-by-value functions compute the passed-in expression's value before calling the function, thus the same value is accessed every time. However, call-by-name functions recompute the passed-in expression's value every time it is accessed.

这是因为按值调用函数在调用函数之前计算传入表达式的值,因此每次都访问相同的值。但是,每次访问传入表达式时,按名称调用函数都会重新计算其值。

EXAMPLES WHERE IT IS BETTER TO USE CALL-BY-NAME

举例来说,最好使用昵称。

From: https://*.com/a/19036068/1773841

来自:https://*.com/a/19036068/1773841

Simple performance example: logging.

简单的性能示例:日志记录。

Let's imagine an interface like this:

让我们想象这样一个界面:

trait Logger {
  def info(msg: => String)
  def warn(msg: => String)
  def error(msg: => String)
}

And then used like this:

然后像这样使用:

logger.info("Time spent on X: " + computeTimeSpent)

If the info method doesn't do anything (because, say, the logging level was configured for higher than that), then computeTimeSpent never gets called, saving time. This happens a lot with loggers, where one often sees string manipulation which can be expensive relative to the tasks being logged.

如果info方法什么都不做(因为日志级别被配置为更高),那么computeTimeSpent就不会被调用,从而节省了时间。这在日志记录器中经常发生,在日志记录器中经常会看到字符串操作,相对于被记录的任务来说,这些操作可能比较昂贵。

Correctness example: logic operators.

正确的例子:逻辑操作符。

You have probably seen code like this:

您可能见过这样的代码:

if (ref != null && ref.isSomething)

Imagine you would declare && method like this:

想象你会这样声明&& &方法:

trait Boolean {
  def &&(other: Boolean): Boolean
}

then, whenever ref is null, you'll get an error because isSomething will be called on a nullreference before being passed to &&. For this reason, the actual declaration is:

然后,当ref为null时,您将得到一个错误,因为在传递给&&之前,isSomething将被调用到nullreference。因此,实际申报是:

trait Boolean {
  def &&(other: => Boolean): Boolean =
    if (this) this else other
}

#9


2  

Call by value is general use case as explained by many answers here..

按值调用是通用用例,这里有许多答案。

Call-by-name passes a code block to the caller and each time the caller accesses the parameter, the code block is executed and the value is calculated.

按名称调用将代码块传递给调用者,每次调用者访问参数时,执行代码块并计算值。

I will try to demonstrate call by name more simple way with use cases below

我将尝试用下面的用例以更简单的方式演示调用的名称

Example 1:

示例1:

Simple example/use case of call by name is below function, which takes function as parameter and gives the time elapsed.

函数下面是按名称调用的简单示例/用例,函数以函数为参数,给出运行时间。

 /**
   * Executes some code block and prints to stdout the 
time taken to execute   the block 
for interactive testing and debugging.
   */
  def time[T](f: => T): T = {
    val start = System.nanoTime()
    val ret = f
    val end = System.nanoTime()

    println(s"Time taken: ${(end - start) / 1000 / 1000} ms")

    ret
  }

Example 2:

示例2:

apache spark (with scala) uses logging using call by name way see Logging trait in which its lazily evaluates whether log.isInfoEnabled or not from the below method.

apache spark(带有scala)使用按名称调用的方式使用日志记录,请参阅日志记录特征,其中它延迟地计算日志。isInfoEnabled or not from the below method。

protected def logInfo(msg: => String) {
     if (log.isInfoEnabled) log.info(msg)
 }

#10


1  

Parameters are usually pass by value, which means that they'll be evaluated before being substituted in the function body.

参数通常通过值传递,这意味着在函数体中替换参数之前,将对它们进行评估。

You can force a parameter to be call by name by using the double arrow when defining the function.

在定义函数时,可以使用双箭头强制参数按名称调用。

// first parameter will be call by value, second call by name, using `=>`
def returnOne(x: Int, y: => Int): Int = 1

// to demonstrate the benefits of call by name, create an infinite recursion
def loop(x: Int): Int = loop(x)

// will return one, since `loop(2)` is passed by name so no evaluated
returnOne(2, loop(2))

// will not terminate, since loop(2) will evaluate. 
returnOne(loop(2), 2) // -> returnOne(loop(2), 2) -> returnOne(loop(2), 2) -> ... 

#11


1  

Going through an example should help you better understand the difference.

通过一个例子可以帮助您更好地理解差异。

Let's definie a simple function that returns the current time:

让我们定义一个返回当前时间的简单函数:

def getTime = System.currentTimeMillis

Now we'll define a function, by name, that prints two times delayed by a second:

现在我们定义一个函数,按名字,打印延迟一秒的两倍:

def getTimeByName(f: => Long) = { println(f); Thread.sleep(1000); println(f)}

And a one by value:

和一个按值的1:

def getTimeByValue(f: Long) = { println(f); Thread.sleep(1000); println(f)}

Now let's call each:

现在让我们打电话:

getTimeByName(getTime)
// prints:
// 1514451008323
// 1514451009325

getTimeByValue(getTime)
// prints:
// 1514451024846
// 1514451024846

The result should explain the difference. The snippet is available here.

结果应该能解释这种差异。这段代码可以在这里找到。

#12


0  

CallByName is invoked when used and callByValue is invoked whenever the statement is encountered.

当遇到语句时调用CallByName,并调用callByValue。

For example:-

例如:-

I have a infinite loop i.e. if you execute this function we will never get scala prompt.

我有一个无限循环,如果你执行这个函数,我们永远不会得到scala提示符。

scala> def loop(x:Int) :Int = loop(x-1)
loop: (x: Int)Int

a callByName function takes above loop method as an argument and it is never used inside its body.

callByName函数作为一个参数接受上面的循环方法,它从来没有在它的内部使用过。

scala> def callByName(x:Int,y: => Int)=x
callByName: (x: Int, y: => Int)Int

On execution of callByName method we don't find any problem ( we get scala prompt back ) as we are no where using the loop function inside callByName function.

在执行callByName方法时,我们没有发现任何问题(我们得到了scala提示符),因为在callByName函数中我们没有使用循环函数。

scala> callByName(1,loop(10))
res1: Int = 1
scala> 

a callByValue function takes above loop method as a parameter as a result inside function or expression is evaluated before executing outer function there by loop function executed recursively and we never get scala prompt back.

callByValue函数将上述循环方法作为参数,因此在函数或表达式中执行递归执行外部函数之前,会对函数或表达式求值,我们永远不会得到scala提示符。

scala> def callByValue(x:Int,y:Int) = x
callByValue: (x: Int, y: Int)Int

scala> callByValue(1,loop(1))

#13


0  

I don't think all the answers here do the correct justification:

我不认为所有的答案都是正确的:

In call by value the arguments are computed just once:

按值调用,参数只计算一次:

def f(x : Int, y :Int) = x

// following the substitution model

f(12 + 3, 4 * 11)
f(15, 4194304)
15

you can see above that all the arguments are evaluated whether needed are not, normally call-by-value can be fast but not always like in this case.

您可以在上面看到,所有的参数都被评估是否需要,通常按值调用可以很快,但并不总是像本例中那样。

If the evaluation strategy was call-by-name then the decomposition would have been:

如果评价策略是按名称调用,则分解将是:

f(12 + 3, 4 * 11)
12 + 3
15

as you can see above we never needed to evaluate 4 * 11 and hence saved a bit of computation which may be beneficial sometimes.

正如您所看到的,我们从不需要对4 * 11进行评估,因此节省了一些可能有时是有益的计算。

#14


0  

See this:

看到这个:

    object NameVsVal extends App {

  def mul(x: Int, y: => Int) : Int = {
    println("mul")
    x * y
  }
  def add(x: Int, y: Int): Int = {
    println("add")
    x + y
  }
  println(mul(3, add(2, 1)))
}

y: => Int is call by name. What is passed as call by name is add(2, 1). This will be evaluated lazily. So output on console will be "mul" followed by "add", although add seems to be called first. Call by name acts as kind of passing a function pointer.
Now change from y: => Int to y: Int. Console will show "add" followed by "mul"! Usual way of evaluation.

y: => Int是按名称调用。通过名称的调用传递的是add(2,1),这将被延迟评估。因此控制台的输出将是“mul”,然后是“add”,尽管add似乎是首先被调用的。通过名称调用就像传递函数指针一样。现在从y: => Int改为y: Int.控制台显示“add”,后面跟着“mul”!通常的评价方式。

#15


0  

According to Martin Odersky :

根据马丁·奥德斯基的说法:

Both strategies reduce to the same final values as long as :

只要:

  • the reduced expression consists of pure functions, and
  • 还原的表达式由纯函数组成。
  • both evaluations terminate.
  • 两个评估终止。

Call-by-value has the advantage that it evaluates every function argument only once.

按值调用的优点是它只计算每个函数参数一次。

Call-by-name has the advantage that a function argument is not evaluated if the corresponding parameter is unused in the evaluation of the function body.

如果在函数体的求值中没有使用相应的参数,那么按名称调用的优点是函数参数不会被求值。

在Scala中调用名称vs调用,需要澄清。

#16


0  

In a Call by Value, the value of the expression is pre-computed at the time of the function call and that particular value is passed as the parameter to the corresponding function. The same value will be used all throughout the function.

在值的调用中,表达式的值在函数调用时预先计算,并且该值作为参数传递给相应的函数。在整个函数中都将使用相同的值。

Whereas in a Call by Name, the expression itself is passed as a parameter to the function and it is only computed inside the function, whenever that particular parameter is called.

而在名称的调用中,表达式本身作为参数传递给函数,并且只有在调用特定参数时才会在函数中计算。

The difference between Call by Name and Call by Value in Scala could be better understood with the below example:

下面的例子可以更好地理解Scala中的名称和调用之间的区别:

Code Snippet

代码片段

object CallbyExample extends App {

  // function definition of call by value
  def CallbyValue(x: Long): Unit = {
    println("The current system time via CBV: " + x);
    println("The current system time via CBV " + x);
  }

  // function definition of call by name
  def CallbyName(x: => Long): Unit = {
    println("The current system time via CBN: " + x);
    println("The current system time via CBN: " + x);
  }

  // function call
  CallbyValue(System.nanoTime());
  println("\n")
  CallbyName(System.nanoTime());
}

Output

输出

The current system time via CBV: 1153969332591521
The current system time via CBV 1153969332591521


The current system time via CBN: 1153969336749571
The current system time via CBN: 1153969336856589

In the above code snippet, for the function call CallbyValue(System.nanoTime()), the system nano time is pre-calculated and that pre-calculated value has been passed a parameter to the function call.

在上面的代码片段中,对于函数调用CallbyValue(system . nanotime()),系统nano时间是预先计算的,并且预计算的值已经被传递给函数调用的一个参数。

But in the CallbyName(System.nanoTime()) function call, the expression "System.nanoTime())" itself is passed as a parameter to the function call and the value of that expression is calculated when that parameter is used inside the function.

但是在CallbyName(System.nanoTime())函数调用中,表达式“System.nanoTime()”本身作为参数传递给函数调用,当在函数中使用该参数时,将计算表达式的值。

Notice the function definition of the CallbyName function, where there is a => symbol separating the parameter x and its datatype. That particular symbol there indicates the function is of call by name type.

请注意CallbyName函数的函数定义,其中有一个=>符号分隔参数x及其数据类型。这里的特定符号表明函数是按名称类型调用的。

In other words, the call by value function arguments are evaluated once before entering the function, but the call by name function arguments are evaluated inside the function only when they are needed.

换句话说,在输入函数之前,对值函数参数的调用进行一次计算,但是只在需要的时候,才在函数内部对名称函数参数的调用进行计算。

Hope this helps!

希望这可以帮助!

#1


421  

The example you have given only uses call-by-value, so I will give a new, simpler, example that shows the difference.

您所给出的示例仅使用了调用的值,因此我将给出一个新的、更简单的示例,以显示不同之处。

First, let's assume we have a function with a side-effect. This function prints something out and then returns an Int.

首先,假设我们有一个具有副作用的函数。这个函数输出一些东西,然后返回一个Int。

def something() = {
  println("calling something")
  1 // return value
}

Now we are going to define two function that accept Int arguments that are exactly the same except that one takes the argument in a call-by-value style (x: Int) and the other in a call-by-name style (x: => Int).

现在我们将定义两个接受Int参数的函数,它们是完全相同的,除了其中一个参数是按值调用样式(x: Int),另一个是按名称调用样式(x: => Int)。

def callByValue(x: Int) = {
  println("x1=" + x)
  println("x2=" + x)
}

def callByName(x: => Int) = {
  println("x1=" + x)
  println("x2=" + x)
}

Now what happens when we call them with our side-effecting function?

当我们用副作用函数调用它们时会发生什么呢?

scala> callByValue(something())
calling something
x1=1
x2=1

scala> callByName(something())
calling something
x1=1
calling something
x2=1

So you can see that in the call-by-value version, the side-effect of the passed-in function call (something()) only happened once. However, in the call-by-name version, the side-effect happened twice.

因此,您可以看到,在按值的版本中,传入函数调用的副作用(某些())只发生一次。然而,在按名字调用的版本中,副作用发生了两次。

This is because call-by-value functions compute the passed-in expression's value before calling the function, thus the same value is accessed every time. However, call-by-name functions recompute the passed-in expression's value every time it is accessed.

这是因为按值调用函数在调用函数之前计算传入表达式的值,因此每次都访问相同的值。然而,在每次访问时,调用的名称函数都会重新计算传入表达式的值。

#2


43  

Here is an example from Martin Odersky:

这是Martin Odersky的一个例子:

def test (x:Int, y: Int)= x*x

We want to examine the evaluation strategy and determine which one is faster (less steps) in these conditions:

我们希望检查评估策略,并确定在这些条件下哪个是更快的(更少的步骤):

test (2,3)

call by value: test(2,3) -> 2*2 -> 4
call by name: test(2,3) -> 2*2 -> 4
Here the result is reached with the same number of steps.

按值调用:test(2,3) -> 2*2 -> 4按名称调用:test(2,3) -> 2*2 ->

test (3+4,8)

call by value: test (7,8) -> 7*7 -> 49
call by name: (3+4) (3+4) -> 7(3+4)-> 7*7 ->49
Here call by value is faster.

按值调用:test(7,8) -> 7*7 ->49按名称调用:(3+4)(3+4)-> 7(3+4)-> 7*7 ->49按值调用更快。

test (7,2*4)

call by value: test(7,8) -> 7*7 -> 49
call by name: 7 * 7 -> 49
Here call by name is faster

按值调用:test(7,8) -> 7*7 -> 49按名字调用:7*7 -> 49这里按名字调用更快

test (3+4, 2*4) 

call by value: test(7,2*4) -> test(7, 8) -> 7*7 -> 49
call by name: (3+4)(3+4) -> 7(3+4) -> 7*7 -> 49
The result is reached within the same steps.

调用值:test(7,2*4) -> test(7, 8) -> 7*7 -> 49调用名:(3+4)-> 7(3+4)-> 7*7 -> 49

#3


14  

In the case of your example all the parameters will be evaluated before it's called in the function , as you're only defining them by value. If you want to define your parameters by name you should pass a code block:

在示例中,所有参数将在函数中调用之前进行计算,因为您只是按值定义它们。如果您想按名称定义参数,您应该传递一个代码块:

def f(x: => Int, y:Int) = x

This way the parameter x will not be evaluated until it's called in the function.

这样,参数x在函数调用之前不会被计算。

This little post here explains this nicely too.

这里的这篇文章也很好地解释了这一点。

#4


7  

I will try to explain by a simple use case rather than by just providing an example

我将尝试用一个简单的用例来解释,而不是仅仅提供一个示例

Imagine you want to build a "nagger app" that will Nag you every time since time last you got nagged.

假设你想要构建一个“nagger应用程序”,它会在你上次被人骚扰之后每次都唠叨你。

Examine the following implementations:

检查以下的实现:

object main  {

    def main(args: Array[String]) {

        def onTime(time: Long) {
            while(time != time) println("Time to Nag!")
            println("no nags for you!")
        }

        def onRealtime(time: => Long) {
            while(time != time) println("Realtime Nagging executed!")
        }

        onTime(System.nanoTime())
        onRealtime(System.nanoTime())
    }
}

In the above implementation the nagger will work only when passing by name the reason is that, when passing by value it will re-used and therefore the value will not be re-evaluated while when passing by name the value will be re-evaluated every time the variables is accessed

在上面的实现中,nagger只在传递name时才会工作,原因是,当传递value时,它将被重用,因此当传递name时,该值将不会被重新评估,而每次访问变量时,该值将被重新评估

#5


6  

To iteratate @Ben's point in the above comments, I think it's best to think of "call-by-name" as just syntactic sugar. The parser just wraps the expressions in anonymous functions, so that they can be called at a later point, when they are used.

为了在上面的评论中重复@Ben的观点,我认为最好把“按名字叫”看成是语法上的糖。解析器只是将表达式封装在匿名函数中,以便在稍后使用表达式时调用它们。

In effect, instead of defining

实际上,不是定义

def callByName(x: => Int) = {
  println("x1=" + x)
  println("x2=" + x)
}

and running:

并运行:

scala> callByName(something())
calling something
x1=1
calling something
x2=1

You could also write:

你也可以写:

def callAlsoByName(x: () => Int) = {
  println("x1=" + x())
  println("x2=" + x())
}

And run it as follows for the same effect:

并按如下方式运行:

callAlsoByName(() => {something()})

calling something
x1=1
calling something
x2=1

#6


4  

Typically, parameters to functions are by-value parameters; that is, the value of the parameter is determined before it is passed to the function. But what if we need to write a function that accepts as a parameter an expression that we don't want evaluated until it's called within our function? For this circumstance, Scala offers call-by-name parameters.

通常,函数的参数是按值参数;也就是说,参数的值是在传递给函数之前确定的。但是,如果我们需要编写一个函数作为参数接受一个表达式,我们不希望它在函数中被调用之前被求值呢?对于这种情况,Scala提供按名称调用的参数。

A call-by-name mechanism passes a code block to the callee and each time the callee accesses the parameter, the code block is executed and the value is calculated.

按名称调用机制将代码块传递给被调用者,每次被调用者访问参数时,执行代码块并计算值。

object Test {
def main(args: Array[String]) {
    delayed(time());
}

def time() = {
  println("Getting time in nano seconds")
  System.nanoTime
}
def delayed( t: => Long ) = {
  println("In delayed method")
  println("Param: " + t)
  t
}
}
 1. C:/>scalac Test.scala 
 2. scala Test
 3. In delayed method
 4. Getting time in nano seconds
 5. Param: 81303808765843
 6. Getting time in nano seconds

#7


3  

As i assume, the call-by-value function as discuss above pass just the values to the function. According to Martin Odersky It is a Evaluation strategy follow by a Scala that play the important role in function evaluation. But, Make it simple to call-by-name. its like a pass the function as a argument to the method also know as Higher-Order-Functions. When the method access the value of passed parameter, it call the implementation of passed functions. as Below:

正如我所假设的,上面讨论的按值调用函数只将值传递给函数。根据Martin Odersky的观点,这是Scala之后的一种评估策略,在函数评估中扮演着重要的角色。但是,要简化按名字调用的过程。它就像把函数作为参数传递给方法,方法也称为高阶函数。当方法访问传递参数的值时,它调用传递函数的实现。如下:

According to @dhg example, create the method first as:

根据@dhg示例,首先创建方法为:

def something() = {
 println("calling something")
 1 // return value
}  

This function contain one println statement and return an integer value. Create the function, who have arguments as a call-by-name:

这个函数包含一个println语句并返回一个整数值。创建函数,其参数为按名称调用:

def callByName(x: => Int) = {
 println("x1=" + x)
 println("x2=" + x)
}

This function parameter, is define an anonymous function who have return one integer value. In this x contain an definition of function who have 0 passed arguments but return int value and our something function contain same signature. When we call the function, we pass the function as a argument to callByName. But in the case of call-by-value its only pass the integer value to the function. We call the function as below:

这个函数参数是定义一个匿名函数,它返回一个整数值。在这个x中包含一个函数的定义,该函数的参数为0,但返回int值,我们的某某函数包含相同的签名。当我们调用函数时,我们将函数作为参数传递给callByName。但是对于按值调用,它只将整数值传递给函数。我们将该函数称为:

scala> callByName(something())
 calling something
 x1=1
 calling something
 x2=1 

In this our something method called twice, because when we access the value of x in callByName method, its call to the defintion of something method.

在这个东西方法中,我们调用了两次,因为当我们在callByName方法中访问x的值时,它调用了一个方法的定义。

#8


2  

There are already lots of fantastic answers for this question in Internet. I will write a compilation of several explanations and examples I have gathered about the topic, just in case someone may find it helpful

互联网上已经有很多关于这个问题的奇妙答案了。我将把我收集到的关于这个主题的几个解释和例子汇编在一起,以防有人发现它有用

INTRODUCTION

介绍

call-by-value (CBV)

cb v值()都未

Typically, parameters to functions are call-by-value parameters; that is, the parameters are evaluated left to right to determine their value before the function itself is evaluated

通常,函数的参数是按值调用的参数;也就是说,在对函数本身进行求值之前,从左到右对参数进行求值

def first(a: Int, b: Int): Int = a
first(3 + 4, 5 + 6) // will be reduced to first(7, 5 + 6), then first(7, 11), and then 7

call-by-name (CBN)

call-by-name(CBN)

But what if we need to write a function that accepts as a parameter an expression that we don't to evaluate until it's called within our function? For this circumstance, Scala offers call-by-name parameters. Meaning the parameter is passed into the function as it is, and its valuation takes place after substitution

但是,如果我们需要编写一个函数,它接受一个参数,一个表达式,我们在函数中调用它之前不需要对它求值呢?对于这种情况,Scala提供按名称调用的参数。意思是把参数按原样传递到函数中,并在替换后进行赋值

def first1(a: Int, b: => Int): Int = a
first1(3 + 4, 5 + 6) // will be reduced to (3 + 4) and then to 7

A call-by-name mechanism passes a code block to the call and each time the call accesses the parameter, the code block is executed and the value is calculated. In the following example, delayed prints a message demonstrating that the method has been entered. Next, delayed prints a message with its value. Finally, delayed returns ‘t’:

按名称调用机制将代码块传递给调用,每次调用访问参数时,执行代码块并计算值。在下面的示例中,延迟打印一条消息,说明方法已经输入。接下来,delay打印一个带有其值的消息。最后,推迟返回“t”:

 object Demo {
       def main(args: Array[String]) {
            delayed(time());
       }
    def time() = {
          println("Getting time in nano seconds")
          System.nanoTime
       }
       def delayed( t: => Long ) = {
          println("In delayed method")
          println("Param: " + t)
       }
    }

In delayed method
Getting time in nano seconds
Param: 2027245119786400

在延迟方法中,以纳秒为单位获取时间:2027245119786400

PROS AND CONS FOR EACH CASE

每种情况的利弊

CBN: +Terminates more often * check below above termination * + Has the advantage that a function argument is not evaluated if the corresponding parameter is unused in the evaluation of the function body -It is slower, it creates more classes (meaning the program takes longer to load) and it consumes more memory.

CBN:+终止更多*检查以下终止* +以上的优点是函数参数不是评估如果相应的参数是未使用的评价函数体——是慢的,它创造了更多的类(即程序需要更长的时间来加载),它会消耗更多的内存。

CBV: + It is often exponentially more efficient than CBN, because it avoids this repeated recomputation of arguments expressions that call by name entails. It evaluates every function argument only once + It plays much nicer with imperative effects and side effects, because you tend to know much better when expressions will be evaluated. -It may lead to a loop during its parameters evaluation * check below above termination *

它通常比CBN效率更高,因为它避免了按名称调用的参数表达式的重复计算。它只对每个函数参数求值一次+它在执行效果和副作用方面表现得更好,因为当表达式被求值时,您往往知道得更好。-在其参数评估过程中可能导致循环*在上述终止项下检查*

What if termination is not guaranteed?

如果终止没有保证怎么办?

-If CBV evaluation of an expression e terminates, then CBN evaluation of e terminates too -The other direction is not true

-如果一个表达式e的CBV评价终止,那么CBN对e的评价也终止——另一个方向不成立

Non-termination example

Non-termination例子

def first(x:Int, y:Int)=x

Consider the expression first(1,loop)

首先考虑的表达式(循环)

CBN: first(1,loop) → 1 CBV: first(1,loop) → reduce arguments of this expression. Since one is a loop, it reduce arguments infinivly. It doesn’t terminate

CBN:首先cb v(1、循环)→1:都未前(1、循环)→减少参数的表达式。因为一个是循环,它减少了不定式的参数。它不会终止

DIFFERENCES IN EACH CASE BEHAVIOUR

每个案例行为的差异。

Let's define a method test that will be

让我们定义一个方法测试

Def test(x:Int, y:Int) = x * x  //for call-by-value
Def test(x: => Int, y: => Int) = x * x  //for call-by-name

Case1 test(2,3)

Case1测试(2、3)

test(2,3)   →  2*2 → 4

Since we start with already evaluated arguments it will be the same amount of steps for call-by-value and call-by-name

因为我们从已经计算过的参数开始,所以按值调用和按名称调用的步骤数量是相同的

Case2 test(3+4,8)

例2测试(3 + 4,8)

call-by-value: test(3+4,8) → test(7,8) → 7 * 7 → 49
call-by-name: (3+4)*(3+4) → 7 * (3+4) → 7 * 7 → 49

In this case call-by-value performs less steps

在这种情况下,按值执行更少的步骤。

Case3 test(7, 2*4)

Case3测试(7、2 * 4)

call-by-value: test(7, 2*4) → test(7,8) → 7 * 7 → 49
call-by-name: (7)*(7) → 49

We avoid the unnecessary computation of the second argument

我们避免不必要地计算第二个参数

Case4 test(3+4, 2*4)

Case4测试(3 + 4,2 * 4)

call-by-value: test(7, 2*4) → test(7,8) → 7 * 7 → 49
call-by-name: (3+4)*(3+4) → 7*(3+4) → 7*7 →  49

Different approach

不同的方法

First, let's assume we have a function with a side-effect. This function prints something out and then returns an Int.

首先,假设我们有一个具有副作用的函数。这个函数输出一些东西,然后返回一个Int。

def something() = {
  println("calling something")
  1 // return value
}

Now we are going to define two function that accept Int arguments that are exactly the same except that one takes the argument in a call-by-value style (x: Int) and the other in a call-by-name style (x: => Int).

现在,我们将定义两个函数,它们接受的是完全相同的Int参数,除了一个以调用-by-value样式(x: Int)和另一个以callby -by-name样式(x: => Int)进行参数转换。

def callByValue(x: Int) = {
  println("x1=" + x)
  println("x2=" + x)
}
def callByName(x: => Int) = {
  println("x1=" + x)
  println("x2=" + x)
}

Now what happens when we call them with our side-effecting function?

当我们用副作用函数调用它们时会发生什么呢?

scala> callByValue(something())
calling something
x1=1
x2=1
scala> callByName(something())
calling something
x1=1
calling something
x2=1

So you can see that in the call-by-value version, the side-effect of the passed-in function call (something()) only happened once. However, in the call-by-name version, the side-effect happened twice.

因此,您可以看到,在按值的版本中,传入函数调用的副作用(某些())只发生一次。然而,在按名字调用的版本中,副作用发生了两次。

This is because call-by-value functions compute the passed-in expression's value before calling the function, thus the same value is accessed every time. However, call-by-name functions recompute the passed-in expression's value every time it is accessed.

这是因为按值调用函数在调用函数之前计算传入表达式的值,因此每次都访问相同的值。但是,每次访问传入表达式时,按名称调用函数都会重新计算其值。

EXAMPLES WHERE IT IS BETTER TO USE CALL-BY-NAME

举例来说,最好使用昵称。

From: https://*.com/a/19036068/1773841

来自:https://*.com/a/19036068/1773841

Simple performance example: logging.

简单的性能示例:日志记录。

Let's imagine an interface like this:

让我们想象这样一个界面:

trait Logger {
  def info(msg: => String)
  def warn(msg: => String)
  def error(msg: => String)
}

And then used like this:

然后像这样使用:

logger.info("Time spent on X: " + computeTimeSpent)

If the info method doesn't do anything (because, say, the logging level was configured for higher than that), then computeTimeSpent never gets called, saving time. This happens a lot with loggers, where one often sees string manipulation which can be expensive relative to the tasks being logged.

如果info方法什么都不做(因为日志级别被配置为更高),那么computeTimeSpent就不会被调用,从而节省了时间。这在日志记录器中经常发生,在日志记录器中经常会看到字符串操作,相对于被记录的任务来说,这些操作可能比较昂贵。

Correctness example: logic operators.

正确的例子:逻辑操作符。

You have probably seen code like this:

您可能见过这样的代码:

if (ref != null && ref.isSomething)

Imagine you would declare && method like this:

想象你会这样声明&& &方法:

trait Boolean {
  def &&(other: Boolean): Boolean
}

then, whenever ref is null, you'll get an error because isSomething will be called on a nullreference before being passed to &&. For this reason, the actual declaration is:

然后,当ref为null时,您将得到一个错误,因为在传递给&&之前,isSomething将被调用到nullreference。因此,实际申报是:

trait Boolean {
  def &&(other: => Boolean): Boolean =
    if (this) this else other
}

#9


2  

Call by value is general use case as explained by many answers here..

按值调用是通用用例,这里有许多答案。

Call-by-name passes a code block to the caller and each time the caller accesses the parameter, the code block is executed and the value is calculated.

按名称调用将代码块传递给调用者,每次调用者访问参数时,执行代码块并计算值。

I will try to demonstrate call by name more simple way with use cases below

我将尝试用下面的用例以更简单的方式演示调用的名称

Example 1:

示例1:

Simple example/use case of call by name is below function, which takes function as parameter and gives the time elapsed.

函数下面是按名称调用的简单示例/用例,函数以函数为参数,给出运行时间。

 /**
   * Executes some code block and prints to stdout the 
time taken to execute   the block 
for interactive testing and debugging.
   */
  def time[T](f: => T): T = {
    val start = System.nanoTime()
    val ret = f
    val end = System.nanoTime()

    println(s"Time taken: ${(end - start) / 1000 / 1000} ms")

    ret
  }

Example 2:

示例2:

apache spark (with scala) uses logging using call by name way see Logging trait in which its lazily evaluates whether log.isInfoEnabled or not from the below method.

apache spark(带有scala)使用按名称调用的方式使用日志记录,请参阅日志记录特征,其中它延迟地计算日志。isInfoEnabled or not from the below method。

protected def logInfo(msg: => String) {
     if (log.isInfoEnabled) log.info(msg)
 }

#10


1  

Parameters are usually pass by value, which means that they'll be evaluated before being substituted in the function body.

参数通常通过值传递,这意味着在函数体中替换参数之前,将对它们进行评估。

You can force a parameter to be call by name by using the double arrow when defining the function.

在定义函数时,可以使用双箭头强制参数按名称调用。

// first parameter will be call by value, second call by name, using `=>`
def returnOne(x: Int, y: => Int): Int = 1

// to demonstrate the benefits of call by name, create an infinite recursion
def loop(x: Int): Int = loop(x)

// will return one, since `loop(2)` is passed by name so no evaluated
returnOne(2, loop(2))

// will not terminate, since loop(2) will evaluate. 
returnOne(loop(2), 2) // -> returnOne(loop(2), 2) -> returnOne(loop(2), 2) -> ... 

#11


1  

Going through an example should help you better understand the difference.

通过一个例子可以帮助您更好地理解差异。

Let's definie a simple function that returns the current time:

让我们定义一个返回当前时间的简单函数:

def getTime = System.currentTimeMillis

Now we'll define a function, by name, that prints two times delayed by a second:

现在我们定义一个函数,按名字,打印延迟一秒的两倍:

def getTimeByName(f: => Long) = { println(f); Thread.sleep(1000); println(f)}

And a one by value:

和一个按值的1:

def getTimeByValue(f: Long) = { println(f); Thread.sleep(1000); println(f)}

Now let's call each:

现在让我们打电话:

getTimeByName(getTime)
// prints:
// 1514451008323
// 1514451009325

getTimeByValue(getTime)
// prints:
// 1514451024846
// 1514451024846

The result should explain the difference. The snippet is available here.

结果应该能解释这种差异。这段代码可以在这里找到。

#12


0  

CallByName is invoked when used and callByValue is invoked whenever the statement is encountered.

当遇到语句时调用CallByName,并调用callByValue。

For example:-

例如:-

I have a infinite loop i.e. if you execute this function we will never get scala prompt.

我有一个无限循环,如果你执行这个函数,我们永远不会得到scala提示符。

scala> def loop(x:Int) :Int = loop(x-1)
loop: (x: Int)Int

a callByName function takes above loop method as an argument and it is never used inside its body.

callByName函数作为一个参数接受上面的循环方法,它从来没有在它的内部使用过。

scala> def callByName(x:Int,y: => Int)=x
callByName: (x: Int, y: => Int)Int

On execution of callByName method we don't find any problem ( we get scala prompt back ) as we are no where using the loop function inside callByName function.

在执行callByName方法时,我们没有发现任何问题(我们得到了scala提示符),因为在callByName函数中我们没有使用循环函数。

scala> callByName(1,loop(10))
res1: Int = 1
scala> 

a callByValue function takes above loop method as a parameter as a result inside function or expression is evaluated before executing outer function there by loop function executed recursively and we never get scala prompt back.

callByValue函数将上述循环方法作为参数,因此在函数或表达式中执行递归执行外部函数之前,会对函数或表达式求值,我们永远不会得到scala提示符。

scala> def callByValue(x:Int,y:Int) = x
callByValue: (x: Int, y: Int)Int

scala> callByValue(1,loop(1))

#13


0  

I don't think all the answers here do the correct justification:

我不认为所有的答案都是正确的:

In call by value the arguments are computed just once:

按值调用,参数只计算一次:

def f(x : Int, y :Int) = x

// following the substitution model

f(12 + 3, 4 * 11)
f(15, 4194304)
15

you can see above that all the arguments are evaluated whether needed are not, normally call-by-value can be fast but not always like in this case.

您可以在上面看到,所有的参数都被评估是否需要,通常按值调用可以很快,但并不总是像本例中那样。

If the evaluation strategy was call-by-name then the decomposition would have been:

如果评价策略是按名称调用,则分解将是:

f(12 + 3, 4 * 11)
12 + 3
15

as you can see above we never needed to evaluate 4 * 11 and hence saved a bit of computation which may be beneficial sometimes.

正如您所看到的,我们从不需要对4 * 11进行评估,因此节省了一些可能有时是有益的计算。

#14


0  

See this:

看到这个:

    object NameVsVal extends App {

  def mul(x: Int, y: => Int) : Int = {
    println("mul")
    x * y
  }
  def add(x: Int, y: Int): Int = {
    println("add")
    x + y
  }
  println(mul(3, add(2, 1)))
}

y: => Int is call by name. What is passed as call by name is add(2, 1). This will be evaluated lazily. So output on console will be "mul" followed by "add", although add seems to be called first. Call by name acts as kind of passing a function pointer.
Now change from y: => Int to y: Int. Console will show "add" followed by "mul"! Usual way of evaluation.

y: => Int是按名称调用。通过名称的调用传递的是add(2,1),这将被延迟评估。因此控制台的输出将是“mul”,然后是“add”,尽管add似乎是首先被调用的。通过名称调用就像传递函数指针一样。现在从y: => Int改为y: Int.控制台显示“add”,后面跟着“mul”!通常的评价方式。

#15


0  

According to Martin Odersky :

根据马丁·奥德斯基的说法:

Both strategies reduce to the same final values as long as :

只要:

  • the reduced expression consists of pure functions, and
  • 还原的表达式由纯函数组成。
  • both evaluations terminate.
  • 两个评估终止。

Call-by-value has the advantage that it evaluates every function argument only once.

按值调用的优点是它只计算每个函数参数一次。

Call-by-name has the advantage that a function argument is not evaluated if the corresponding parameter is unused in the evaluation of the function body.

如果在函数体的求值中没有使用相应的参数,那么按名称调用的优点是函数参数不会被求值。

在Scala中调用名称vs调用,需要澄清。

#16


0  

In a Call by Value, the value of the expression is pre-computed at the time of the function call and that particular value is passed as the parameter to the corresponding function. The same value will be used all throughout the function.

在值的调用中,表达式的值在函数调用时预先计算,并且该值作为参数传递给相应的函数。在整个函数中都将使用相同的值。

Whereas in a Call by Name, the expression itself is passed as a parameter to the function and it is only computed inside the function, whenever that particular parameter is called.

而在名称的调用中,表达式本身作为参数传递给函数,并且只有在调用特定参数时才会在函数中计算。

The difference between Call by Name and Call by Value in Scala could be better understood with the below example:

下面的例子可以更好地理解Scala中的名称和调用之间的区别:

Code Snippet

代码片段

object CallbyExample extends App {

  // function definition of call by value
  def CallbyValue(x: Long): Unit = {
    println("The current system time via CBV: " + x);
    println("The current system time via CBV " + x);
  }

  // function definition of call by name
  def CallbyName(x: => Long): Unit = {
    println("The current system time via CBN: " + x);
    println("The current system time via CBN: " + x);
  }

  // function call
  CallbyValue(System.nanoTime());
  println("\n")
  CallbyName(System.nanoTime());
}

Output

输出

The current system time via CBV: 1153969332591521
The current system time via CBV 1153969332591521


The current system time via CBN: 1153969336749571
The current system time via CBN: 1153969336856589

In the above code snippet, for the function call CallbyValue(System.nanoTime()), the system nano time is pre-calculated and that pre-calculated value has been passed a parameter to the function call.

在上面的代码片段中,对于函数调用CallbyValue(system . nanotime()),系统nano时间是预先计算的,并且预计算的值已经被传递给函数调用的一个参数。

But in the CallbyName(System.nanoTime()) function call, the expression "System.nanoTime())" itself is passed as a parameter to the function call and the value of that expression is calculated when that parameter is used inside the function.

但是在CallbyName(System.nanoTime())函数调用中,表达式“System.nanoTime()”本身作为参数传递给函数调用,当在函数中使用该参数时,将计算表达式的值。

Notice the function definition of the CallbyName function, where there is a => symbol separating the parameter x and its datatype. That particular symbol there indicates the function is of call by name type.

请注意CallbyName函数的函数定义,其中有一个=>符号分隔参数x及其数据类型。这里的特定符号表明函数是按名称类型调用的。

In other words, the call by value function arguments are evaluated once before entering the function, but the call by name function arguments are evaluated inside the function only when they are needed.

换句话说,在输入函数之前,对值函数参数的调用进行一次计算,但是只在需要的时候,才在函数内部对名称函数参数的调用进行计算。

Hope this helps!

希望这可以帮助!