2010-04-08

call by name vs. call by value

假设现在需要在Scala实现一个断言函数,我们该怎么做呢?可能第一反应是下面的代码:
> val assertionEnabled = true
>
> def myAssert(predicate: Boolean) =
>   if (assertionEnabled && !predicate)
>     throw new AssertionError

简单来说,就是我们期望传入一个bool值,然后检查它,比如:myAssert(5 > 3)。看起来很完美,至少一眼看下去简单得无法挑剔。但是,有一个重大问题是:无论断言是否被打开,predicate都会被计算一次。如果写成myAssert(foo(x,y)),则foo(x,y)会被执行一次 -- 虽然接下来因为&&是个短路操作符,myAssert()并不检查该函数的执行结果。这叫call-by-value[1],就是说参数传递给函数之前会先计算出其结果。

Scala除了支持C家族中的call-by-value外还支持call-by-name,代码改动很简单:

-- def myAssert(predicate: Boolean) =
++ def myAssert(predicate: => Boolean) =

我这样,predicate将会在myAssert中求值,而非传入时求值。C程序员会认为 "x = 1"是个赋值语句,而对习惯于FP思维的程序员来说,他们可能倾向另一种解释:x只是个name(label),但它绑定了一个类型为整型的数值1(或者x是个返回整数1的函数)。

参考:
[1]  Evaluation Strategy,http://en.wikipedia.org/wiki/Evaluation_strategy

标签:

0 Comments:

发表评论

<< Home