回答

26

因为我n计算机科学理论和实践的原始概念,函数和子程序几乎没有任何关系。

FORTRAN通常被认为是实现这两种功能的第一种语言,并且证明了它们的区别。 (早期的LISP在这方面也有一些相反的作用,但它在学术界以外的影响甚微)。

从数学的传统(CS仍然是60年代的一部分)开始,函数仅被看作是参数化数学计算的封装,仅用于将数值返回到更大的表达式。你可以称它为“裸”(F = AZIMUTH(SECONDS))仅仅是一个简单的用例。

另一方面,子例程被视为一种方式来命名一组旨在产生某种效果的语句。参数大大提高了它们的可用性,它们被允许返回修改参数值的唯一原因是它们可以报告它们的状态而不必依赖于全局变量。

所以,他们真的没有概念上的连接,除了封装和参数。

真正的问题是:“很多开发者是如何看待它们的?”

而答案是C.

K时+ R最初设计为PDP-11的高级别宏汇编语言类型(可以在PDP-8已经开始?),他们没有硬件独立的妄想。实际上,语言的每个“独特”特征都反映了PDP机器语言和体系结构(请参阅i ++和--i)。其中之一是实现了功能和子程序可以(并且始终)在PDP中以相同的方式实现,除了调用者忽略子例程的返回值(在R0 [,R1]中)。因此诞生了虚空指针,并且在C语言接管了编程的整个世界之后,这种HW/OS实现工件(尽管在几乎每个后续平台上都是如此)的误解与语言语义相同。

3

在纯或效果类型的设置有天渊之别,因为很明显,“不返回任何东西”的方法只对其副作用有用。

这类似于表达式和语句之间的区别,它们可以剔除语言并消除一类通常错误的程序(当然这就是为什么C不这样做))。

举一个小例子,当你区分清楚的表达式和语句,if(x = 3)之间,相对于if(x == 3)在语法上是不正确的(用于使用其中预期的表达的陈述),而不是仅仅一种类型的错误(使用整数预计布尔值)。这也有一个好处,就是禁止if(x = true),在分配是具有右操作数值的表达式的上下文中,基于类型的规则将允许这种做法。

在一个封装单子效果的语言,最重要的区别成为一个之间:返回()这是纯粹的功能,只能返回

  • 函数调用()或一个无用的空值偏离
  • 函数返回IO()(或其他单元中的单元),这些函数除了IO(或其中的任何一个)单元中的效果之外没有“结果”函数
+0

很好的解释,但是,示例表达式似乎假定C. – RBarryYoung 2009-06-19 17:53:17

+0

C清楚地区分表达式和语句。然而,`x = foo`是一个表达式,评估分配的值。这使得某些成语更加简洁(例如fork,不确定迭代)。 – Novelocrat 2009-09-29 22:32:58

0

不好意思回答一个两岁的问题,尤其是独特的,以我自己的语言菲利克斯http://felix-lang.org的东西,但在这里不用反正:)

在菲利克斯,函数和过程是根本不同的,它不仅是程序有副作用并在语句中调用,而函数没有副作用并用于表达式中(因为Felix也具有带副作用函数的生成器。:)

不,执行模型是主要是出于性能方面的原因,但并非完全不同。该模型是:

  • 函数将它们的返回地址放在机器堆栈上,并返回值。
  • 过程使用堆上的链接列表。程序代码是平的,它不使用机器堆栈。

这通常是低效的,那为什么呢?答案是:Felix程序都是潜在的共同程序(纤维)。他们可以通过访问一个通道将控制切换到另一个过程。这导致交换控制权。

  • 由于性能原因,不能在控制交换机器上复制机器堆栈。
  • 由于内存管理的原因,交换堆栈指针也不是一个选项。

操作系统通常交换堆栈指针线程,这是相当快的,但对线性地址机器的一个基本问题:你要么必须堆栈的最大大小限制为一个可笑的小值,或限制线程数量到一个可笑的小值。在32位机器上,没有足够的地址空间来设想这种解决方案。在64位机器上,堆栈交换具有更大的潜力,但当然用户需求在其发布后3天内总是增长超过硬件。:)

Felix只是将一个指针交换到基于堆栈的堆栈,所以上下文切换非常快,而且很少浪费地址空间。当然,成本是程序调用上的堆分配。

在编译器中,理论模型的很多架构都是基于“as-if”优化的,所以实际的性能和实现可能与理论模型有很大不同,前提是编译器可以证明您除了被剥夺机会制作一杯咖啡以外,还有其他的不同:)

所以,在这里,你有一个不同的答案,为什么函数和过程可能会被区别对待。

相关问题