为什么要区分返回值的方法和不返回值的方法?

时间:2009-06-19 14:33:10

标签: language-agnostic programming-languages language-design

为什么某些语言会区分返回值的方法和不返回值的方法?

即。在Oracle的PL / SQL中,函数和过程之间的主要区别在于函数必须返回一个值,并且该过程不能。

对于那些没有的语言,为什么不呢?


编辑:我发现了一个相关问题,人们可能会对阅读这个问题感兴趣:

3 个答案:

答案 0 :(得分:26)

因为在最初的计算机科学理论和实践概念中,函数和子程序实际上彼此无关。

FORTRAN通常被认为是实现这两者的第一语言,并证明了区别。 (早期的LISP在这方面也有一些相反的作用,但它在学术界之外几乎没有影响)。

根据数学传统(CS仍然是60年代的一部分),函数仅被视为参数化数学计算的封装,仅用于将值返回到更大的表达式中。你可以称之为“裸”(F = AZIMUTH(SECONDS))仅仅是一个微不足道的用例。

另一方面,子程序被视为命名一组意图产生一些效果的语句的方法。参数极大地提高了它们的可用性,并且允许它们返回修改后的参数值的唯一原因是它们可以报告它们的状态而不必依赖全局变量。

因此,除封装和参数外,它们实际上没有概念连接。

真正的问题是:“这么多开发人员是如何看待他们一样的?”

答案就是C.

当K + R最初为PDP-11设计他们的高级宏汇编程序类型语言时(可能已经开始使用PDP-8?),他们没有硬件独立性的妄想。实际上,该语言的每个“独特”功能都反映了PDP机器语言和架构(参见i ++和--i)。其中之一是实现功能和子程序可以(并且总是)在PDP中相同地实现,除了调用者忽略了子程序的返回值(在R0 [,R1]中)。

因此诞生了无效指针,并且在C语言接管整个编程世界之后,误认为这个HW / OS实现工件(尽管在几乎每个后续平台上都是正确的)与语言语义相同。

答案 1 :(得分:3)

在纯粹或效果类型的设置中,存在一个与众不同的世界,因为显然“不返回任何东西”的方法仅对其副作用有用。

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

举一个很小的例子,当你清楚地区分表达式和语句时,if(x = 3),而不是if(x == 3)在语法上是不正确的(对于使用表达式是预期的语句)而不仅仅是类型错误(用于使用期望布尔值的整数)。这样做的好处还在于,在赋值是具有右操作数值的表达式的上下文中,基于类型的规则将允许if(x = true)

在一种用monad封装效果的语言中,重要的区别在于:

  • 返回()的函数,它们是纯函数,只能返回一个名为()或发散的无用空值
  • 返回IO ()(或某些其他monad中的单位)的函数,这些函数除了IO(或任何一个)monad中的效果之外没有“结果”的函数

答案 2 :(得分:0)

请原谅我回答一个两年前的问题,尤其是我自己的语言Felix http://felix-lang.org所特有的一些问题,但无论如何都要这样做:)

在Felix中,函数和过程是根本不同的,并且不仅程序有副作用并且在语句中调用,而函数没有副作用并且在表达式中使用(因为Felix也有生成器,是具有副作用的函数.. :)

不,执行模式根本不同,主要是出于性能原因,但并非完全如此。该模型是:

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

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

  • 出于性能原因,无法在控制交换机上复制机器堆栈。
  • 出于内存管理的原因,交换堆栈指针也不是一种选择。

操作系统通常交换线程的堆栈指针,速度相当快,但在线性地址机上有一个基本问题:你要么必须将堆栈的最大大小限制为一个非常小的值,要么限制线程数一个可笑的小价值。在32位机器上,没有足够的地址空间来考虑这个解决方案。在64位计算机上,堆栈交换具有更大的潜力,但当然用户需求在发布3天后总是会超过硬件.. :)

Felix只是将一个指针交换到基于堆的堆栈,因此上下文切换速度非常快,浪费的地址空间非常少。当然,成本是过程调用的堆分配。

在编译器中,理论模型的许多体系结构都在“as-if”的基础上进行优化,因此实际性能和实现可能与理论模型完全不同,前提是编译器可以证明您可以告诉我们不同之处......除了被剥夺了休闲喝咖啡的机会之外:)

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