按名称调用与按宏扩展调用 [英] Call by name vs call by macro expansion

查看:96
本文介绍了按名称调用与按宏扩展调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在非严格的评估语言中,使用按名称调用按宏扩展调用有什么优缺点?

In non strict evaluation languages, what are the differences and advantages/disadvantages of using call by name vs call by macro expansion?

您能否提供一个说明两种评估策略的示例?

Could you provide an example that explains both evaluation strategies?

谢谢!

推荐答案

按姓名致电:

按名称调用是一种评估策略,其中在调用函数之前不评估函数的参数,而是将其直接替换为函数主体(使用捕获避免替换),然后在每次使用它们时对其进行赋值出现在功能中.如果函数主体中未使用参数,则永远不会对参数求值;如果多次使用,则每次出现时都会对其进行重新评估. (请参阅詹森的装置.)

Call by name is an evaluation strategy where the arguments to a function are not evaluated before the function is called—rather, they are substituted directly into the function body (using capture-avoiding substitution) and then left to be evaluated whenever they appear in the function. If an argument is not used in the function body, the argument is never evaluated; if it is used several times, it is re-evaluated each time it appears. (See Jensen's Device.)

按名称进行呼叫评估有时比按值进行呼叫评估更可取.如果在函数中未使用函数的参数,则按名称调用将不评估参数而节省时间,而按值调用将对其进行评估.如果自变量是不间断的计算,则好处是巨​​大的.但是,使用function参数时,按名称调用通常较慢,这需要诸如thunk之类的机制.

Call-by-name evaluation is occasionally preferable to call-by-value evaluation. If a function's argument is not used in the function, call by name will save time by not evaluating the argument, whereas call by value will evaluate it regardless. If the argument is a non-terminating computation, the advantage is enormous. However, when the function argument is used, call by name is often slower, requiring a mechanism such as a thunk.

早期使用的是ALGOL60.当今的.NET语言可以使用委托或Expression参数按名称模拟调用.后者导致将抽象语法树提供给该函数.埃菲尔提供代理,代表需要时要评估的操作. Seed7通过名称提供带有函数参数的调用.

An early use was ALGOL 60. Today's .NET languages can simulate call by name using delegates or Expression parameters. The latter results in an abstract syntax tree being given to the function. Eiffel provides agents, which represent an operation to be evaluated when needed. Seed7 provides call by name with function parameters.

按宏调用:

按宏扩展调用类似于按名称调用,但是使用文本替换而不是避免捕获的替换.如果使用不谨慎,宏替换可能会导致变量捕获并导致不良行为.卫生宏通过检查并替换不是参数的阴影变量来避免此问题.

Call by macro expansion is similar to call by name, but uses textual substitution rather than capture-avoiding substitution. With uncautious use, macro substitution may result in variable capture and lead to undesired behavior. Hygienic macros avoid this problem by checking for and replacing shadowed variables that are not parameters.

注意:采用非严格的评估语言

按宏调用示例:

通过宏扩展调用:许多编程语言,包括C,lisp 和方案,为开发人员提供了一种向其添加新语法的机制 核心语言语法称为宏.宏被扩展为代码 由宏预处理器.这些宏可能包含参数,这些参数 复制到预处理器产生的最终代码中.作为一个 例如,下面的C程序通过宏实现交换功能:

Call by Macro Expansion: many programming languages, including C, lisp and scheme, provide developers with a mechanism to add new syntax to the core language grammar called macros. Macros are expanded into code by a macro preprocessor. These macros might contain arguments, which are copied in the final code that the preprocessor produces. As an example, the C program below implements the swap function via a macro:

#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); } 

此宏实现有效的交换例程.

This macro implements a valid swap routine. The

经过预处理的程序将类似于以下代码.因为身体 宏的代码直接复制到调用程序的文本中, 它在该程序的上下文中运行.换句话说,宏 将直接引用其接收的变量名称,而不是 他们的价值观.

preprocessed program will look like the code below. Because the body of the macro is directly copied into the text of the calling program, it operates on the context of that program. In other words, the macro will refer directly to the variable names that it receives, and not to their values.

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进行两次递增:

The expressions passed to the macro as parameters are evaluated every time they are used in the body of the macro. If the argument is never used, then it is simply not evaluated. As an example, the program below will increment the variable b twice:

#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的一次出现 另一个.例如,下面的程序有一个宏,定义了一个 可变温度main内部的调用导致定义的变量temp 在此函数内部,以通过内部的定义来捕获 宏的身体.

#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); } Macros suffer from one problem, called variable capture. If a macro defines a variable v that is already defined in the environment of the caller, and v is passed to the macro as a parameter, the body of the macro will not be able to distinguish one occurrence of v from the other. For instance, the program below has a macro that defines a variable temp. The call inside main causes the variable temp defined inside this function to be captured by the definition inside the macro's body.

#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预处理程序,我们得到下面的代码.该程序无法执行 交换变量temp和a的值:

the C preprocessor, we get the code below. This program fails to exchange the values of variables temp and a:

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); }

有许多懒惰的评估策略

避免了变量捕获问题.两种最著名的技术 是按名称呼叫和按需呼叫.

that avoid the variable capture problem. The two best known techniques are call-by-name and call-by-need.

按姓名致电示例:

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

Call by Name: in this evaluation strategy the actual parameter is only evaluated if used inside the function; however, this evaluation uses the context of the caller routine. For instance, in the example below, taken from Weber's book, we have a function g that returns the integer 6. Inside the function f, the first assignment, e.g., b = 5, stores 5 in variable i. The second assignment, b = a, reads the value of i, currently 5, and adds 1 to it. This value is then stored at 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的后代,也实现了按名称的调用,正如我们在 这个例子.按名称进行的呼叫始终会导致对 参数,即使多次使用此参数也是如此.这 在参照透明的语言中,这种行为可能是浪费的, 因为在这些语言中,变量是不可变的.

Very few languages implement the call by name evaluation strategy. The most eminent among these languages is Algol. Simula, a direct descendent of Algol, also implements call by name, as we can see in this example. The call by name always causes the evaluation of the parameter, even if this parameter is used multiple times. This behavior might be wasteful in referentially transparent languages, because, in these languages variables are immutable.

这篇关于按名称调用与按宏扩展调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆