CBN Versus CBV
所有的笔记都来自于对于coursea上洛桑联邦理工学院的Scala 函数式程序设计原理课程的理解和摘录。
scala中两种求值策略, call-by-value(CBV,应用序求值)和call-by-name(CBN,正则序求值)。
如果化简表达式由单纯的表达式构成,并且它们都会终止,不陷入循环,那么两种求值策略的结果是相同的,但是它们各有优势。
CBV优势在于函数的每个参数只会被求值一次。
CBN优势在于如果函数参数在函数体中没有被调用,那么就不需要计算它。
举个例子:
def test(x: Int, y:Int) = x*x
test(2,3)
test(3+4,8)
test(7,2*4)
test(3+4,2*4)
test(2,3)
CBV和CBN一样test(3+4,8)
CBV:−>test(7,8)−>7×7−>49
CBN:−>(3+4)×(3+4)−>7×(3∗4)−>7×7−>49
CBN要多一步test(7,2*4)
CBV:−>test(7,8)−>7×7−>49
CBN:−>7×7−>49
CBV要多一步test(3+4,2*4)
CBV:−>test(7,2×4)−>test(7,8)−>7×7−>49
CBN:−>(3+4)×(3+4)−>7×(3∗4)−>7×7−>49
CBN和CBV步数一样
这下CBN和CBV的区别就清楚了,对于CBN函数的所有参数都要求完值之后再代入函数进行运算,而CBV是直接将表达式代入函数。接下来我们再来看一个不终止的例子来进一步加深对它们的理解:
def first(x: Int, y:Int) = x
def loop: Int = loop
first(1,loop)
对于CBN,运行first(1,loop),我们将得到值1。
对于CBV,运行first(1,loop),我们将陷入循环,无法终止,因为CBV一定要求出loop的值才行。
scala中我们一般运用CBV,因为在实际的运算中,CBV往往会非常高效相较于CBN,因为它避免了大量的重复运算。如果我们有时候需要采用CBN,我们该如何操作呢。给出如下示例:
def constOne(x: Int, y: => Int) = 1
这样的话,对于参数x,我们采用CBV,而参数y,我们采用CBN。
同时在定义的时候,也有“by-name”和“by-value”的差别
def loop:Boolean = loop
def x = loop
val x = loop
def的话没关系,而val的话将陷入循环,无法终止,因为val在定义的时候就要算出值来。