Bar*_*Das 18 evaluation programming-languages evaluation-strategy call-by-value call-by-need
我想知道什么是需要的电话.
虽然我在维基百科搜索并在此处找到它:http://en.wikipedia.org/wiki/Evaluation_strategy,但无法正确理解.如果有人可以用一个例子来解释并指出与按值调用的差异,那将是一个很大的帮助.
Rya*_*per 33
假设我们有这个功能
square(x) = x * x
Run Code Online (Sandbox Code Playgroud)
我们想评估square(1+2).
在按值调用时,我们这样做
square(1+2)square(3)3*39在我们这样做的名义呼吁中
square(1+2)(1+2)*(1+2)3*(1+2)3*39请注意,既然我们使用了两次参数,我们会对它进行两次评估.如果论证评估需要很长时间,那将是浪费.这就是需要修复的问题.
在按需调用时,我们执行以下操作:
square(1+2)let x = 1+2 in x*xlet x = 3 in x*x3*39在第2步中,我们不是复制参数(比如在call-by-name中),而是给它起一个名字.然后在步骤3中,当我们注意到我们需要值时x,我们计算表达式x.只有这样我们才能替代.
顺便说一句,如果参数表达式产生了一些更复杂的东西,比如一个闭包,那么可能会有更多的lets,以消除复制的可能性.记下正式规则有点复杂.
请注意,我们"需要"原始操作的参数值,如+和*,但对于其他函数,我们采用"名称,等待和查看"方法.我们可以说原始算术运算是"严格的".它取决于语言,但通常最原始的操作是严格的.
另请注意,"评估"仍然意味着减少到一个值.函数调用始终返回值,而不是表达式.(其中一个答案是错误的.)OTOH,懒惰语言通常具有惰性数据构造函数,它可以具有在需要时评估的组件,即,在提取时.这就是你可以拥有一个"无限"列表的方式---你返回的值是一个懒惰的数据结构.但是,对于懒惰与严格的数据结构,按需调用和按值调用是一个单独的问题.Scheme具有惰性数据构造函数(流),但由于Scheme是按值调用的,因此构造函数是语法形式,而不是普通函数.Haskell是按名称调用的,但它有定义严格数据类型的方法.
如果考虑实现是有帮助的,那么call-by- name的一个实现是将每个参数包装在thunk中; 当需要参数时,你调用thunk并使用该值.需求呼叫的一个实现是类似的,但是thunk是memoizing; 它只运行一次计算,然后保存它,然后只返回保存的答案.
Jak*_*mpl 10
想象一个功能:
fun add(a, b) {
return a + b
}
Run Code Online (Sandbox Code Playgroud)
然后我们称之为:
add(3 * 2, 4 / 2)
Run Code Online (Sandbox Code Playgroud)
在按名称调用语言中,将对此进行评估:
a = 3 * 2 = 6b = 4 / 2 = 2return a + b = 6 + 2 = 8该函数将返回该值8.
在按需调用(也称为惰性语言)中,这样评估如下:
a = 3 * 2b = 4 / 2return a + b = 3 * 2 + 4 / 2该函数将返回表达式3 * 2 + 4 / 2.到目前为止,几乎没有花费任何计算资源.只有在需要它的值时才会计算整个表达式 - 比方说我们要打印结果.
为什么这有用?两个原因.首先,如果您不小心包含死代码,它不会降低您的程序权重,因此可以更高效.其次它允许做很酷的事情,比如用无限列表进行有效计算:
fun takeFirstThree(list) {
return [list[0], list[1], list[2]]
}
takeFirstThree([0 ... infinity])
Run Code Online (Sandbox Code Playgroud)
尝试按名称语言挂起尝试创建从0到无穷大的列表.懒惰的语言将简单地返回[0,1,2].