回答
调用由名称:
通过名字来称呼是在参数的函数不被评估为被叫,而函数之前,它们直接代入函数体的评估策略(使用捕获 - 避免替换),然后在函数中出现时进行评估。如果在函数体中没有使用参数,则参数永远不会被计算;如果多次使用,每次出现时都会重新评估。 (请参阅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中可能会浪费,因为在这些语言中变量是不可变的。
- 1. 通过名称自动呼叫值
- 2. 呼叫通过“串”
- 3. 呼叫通过接口
- 4. 呼叫通过反射
- 5. JSP呼叫通过HREF
- 6. 呼叫通过反射
- 7. 通过AJAX呼叫PHP
- 8. 斯卡拉流按需呼叫(懒惰)vs按名称呼叫
- 9. 星号呼叫文件呼叫未通过
- 10. Android呼叫状态通过“呼叫”类(API 23)
- 11. 查看呼叫器结束后通过意向呼叫活动
- 12. Twilio网络挂接(的NodeJS) - 在呼入呼叫,通过呼叫的SID
- 13. 呼叫在Magento的扩展
- 14. 呼叫wPaint扩展功能
- 15. 通过名称而不是ID来呼叫Wordpress类别
- 16. 通过名称与正常顺序的呼叫
- 17. 呼叫时通过按引用
- 18. 通过引用与QVector呼叫
- 19. Android的修改呼叫通过AOSP
- 20. 的fancybox - 如何通过人工呼叫
- 21. 通过https的Ajax呼叫SSL
- 22. 无法通过活动呼叫服务
- 23. 通过跨域JavaScript呼叫预防CSRF
- 24. 通过DMZ进行代理呼叫
- 25. VoIP呼叫如何通过防火墙
- 26. 呼叫控制器动作通过JavaScript
- 27. 通过https访问PHP Soap呼叫
- 28. 通过意向发起SIP呼叫
- 29. URL呼叫通过文本字符串
- 30. 通过鼠标点击呼叫功能
感谢@sugansoft,但这看起来像https://en.wikibooks.org/wiki/Introduction_to_Programming_Languages/Evaluation_Strategies中的复制粘贴。您的答案中并未详细说明两种评估策略之间的差异和优势/劣势。 –