2017-06-12 218 views

回答

2

调用由名称:

通过名字来称呼是在参数的函数不被评估为被叫,而函数之前,它们直接代入函数体的评估策略(使用捕获 - 避免替换),然后在函数中出现时进行评估。如果在函数体中没有使用参数,则参数永远不会被计算;如果多次使用,每次出现时都会重新评估。 (请参阅Jensen的设备。)

名称评估有时候更适用于按价值评估。如果在函数中没有使用函数的参数,那么通过名称调用将通过不评估参数来节省时间,而按值调用将会评估它。如果参数是非终止计算,优点是巨大的。但是,当使用函数参数时,按名称调用通常比较慢,需要使用thunk等机制。

早期使用的是ALGOL 60.今天的.NET语言可以使用委托或表达式参数按名称模拟调用。后者导致为函数提供一个抽象语法树。艾菲尔提供代理,代表需要时评估的操作。 Seed7通过名称和功能参数提供呼叫。

调用由宏:

通过电话宏展开类似的名字来称呼,但使用文本替换,而不是捕捉避免替代。在不谨慎使用的情况下,宏观替代可能导致变量捕获并导致不希望的行为。卫生宏通过检查并替换不是参数的阴影变量来避免此问题。

注:在非严格的评价语言

实例调用由宏:

呼叫由宏扩展:许多编程语言,包括C,口齿不清 和方案,为开发者提供一种将新语法添加到名为宏的核心语言语法 的机制。宏由宏预处理器扩展为代码 。这些宏可能包含参数,其中 被复制到预处理器生成的最终代码中。作为一个 例如,C程序下面经由宏实现交换功能:

#define SWAP(X,Y) {int temp=X; X=Y; Y=temp;} int main() { int a = 2; int b = 3; printf("%d, %d\n", a, b); SWAP(a, b); printf("%d, 
> %d\n", a, b); } 

该宏实现有效的交换例程。

预处理程序看起来像下面的代码。因为宏的主体 直接复制到调用程序的文本中,所以它在该程序的上下文中操作。换句话说,宏 将直接引用它接收的变量名称,而不是 它们的值。

int main() { int a = 2; int b = 3; printf("%d, %d\n", a, b); { 
> int tmp = (a); (a) = (b); (b) = tmp; }; printf("%d, %d\n", a, b); } 

传递给宏表达式作为参数进行评估它们在宏观的主体中使用的每个 时间。如果参数从不使用 ,那么它就不会被评估。例如,下面的程序 会使变量b增加两次:

#define MAX(X, Y) ((X) > (Y) ? (X) : (Y)) int main() { int a = 2, b = 3; int c = MAX(a, b++); printf("a = %d, b = %d, c = %d\n", a, b, c); }宏受到一个问题的困扰,称为变量捕获。如果一个 宏定义了一个变量v,该变量v已经在调用方的环境 中定义,并且v作为参数传递给宏,宏的主体 将无法​​区分v的一次出现与 其他。例如,下面的程序有一个宏,它定义了一个 变量temp。主函数内部的调用导致该函数内部定义的变量temp被定义为 宏内部的定义。

#define SWAP(X,Y) {int temp=X; X=Y; Y=temp;} int main() { int a = 2; int temp = 17; printf("%d, temp = %d\n", a, temp); SWAP(a, temp); 
> printf("%d, temp = %d\n", a, temp); } 

一旦这个程序是由

C预处理程序扩展,我们可以得到下面的代码。此程序无法 交换变量温度和值:

int main() { int a = 2; int temp = 17; printf("%d, temp = %d\n", 
> a, temp); {int temp=a; a=temp; temp=temp;}; printf("%d, temp = 
> %d\n", a, temp); } 

有一些懒惰的评估策略

是避免变量捕捉问题。两种最着名的技术 分别是按名称和按需呼叫。

示例呼叫用名字:

打电话名称:在该评价中的策略,如果在函数内部中使用的实际参数仅 评价;但是,此评估使用调用程序例程的上​​下文 。例如,在下面的例子中, 取自韦伯的书,我们有一个函数g,返回整数 6.在函数f中,第一个赋值,例如b = 5,将5存储在变量i中。第二个作业b = a读取当前为5的i, 的值,并将其加1。这个值然后存储在i处。

void f(by-name int a, by-name int b) { 
    b=5; 
    b=a; 
} 
int g() { 
    int i = 3; 
    f(i+1,i); 
    return i; 
} 

很少有语言实现通过名称评估策略调用。在这些语言中最着名的 是Algol。 Simula,Algol的后代直接 ,也实现了通过名称的呼叫,我们可以在 这个例子中看到。即使此参数多次使用,通过名称的呼叫始终会导致对参数 的评估。这种 行为在引用透明的语言012ff中可能会浪费,因为在这些语言中变量是不可变的。

+0

感谢@sugansoft,但这看起来像https://en.wikibooks.org/wiki/Introduction_to_Programming_Languages/Evaluation_Strategies中的复制粘贴。您的答案中并未详细说明两种评估策略之间的差异和优势/劣势。 –