"功能"和"程序"有什么区别?

rpr*_*rpr 187 terminology procedure function

一般来说,我们都听说过编程语言中的函数过程.但是,我发现我几乎可以互换地使用这些术语(这可能是非常错误的).

所以,我的问题是:

它们的功能,用途和用途有何不同?

一个例子将不胜感激.

Too*_*the 280

函数返回一个值,一个过程只执行命令.

名称功能来自数学.它用于根据输入计算值.

过程是一组可以按顺序执行的命令.

在大多数编程语言中,甚至函数都可以有一组命令.因此,差异仅在于返回值部分.

但是如果你想保持一个功能干净,(只看功能语言),你需要确保一个功能没有副作用.

  • 在pascal中,过程没有return语句,只有函数有.必须是文本中的错误.但是,一个过程可以有一个"exit"语句,它可以作为没有参数的"return"语句,这意味着没有返回值. (3认同)
  • @orlybg,在声明性语言中,一致性来自于语言的实现。它们的范围限制可防止它们产生副作用。另一方面,命令式语言显式地利用了它们的副作用。副作用并不总是坏的。 (2认同)

jpa*_*cek 40

这取决于具体情况.

在类似Pascal的语言中,函数和过程是不同的实体,不同的是它们是否返回值.他们表现得与众不同.语言语法(例如,过程调用表单语句;您不能在表达式中使用过程调用,而函数调用不会形成语句,您必须在其他语句中使用它们).因此,Pascal-bred程序员区分它们.

在类C语言和许多其他当代语言中,这种区别已经消失; 在静态类型语言中,过程只是具有有趣返回类型的函数.这可能是他们互换使用的原因.

在函数式语言中,通常没有程序这样的东西 - 一切都是函数.

  • 编程语言的文档可以随意调用函数和过程,因为人们会接受任何名称,因为这些名称背后的背景早已被洗掉了。 (2认同)

小智 16

C中的示例:

// function
int square( int n ) {
   return n * n;
}

// procedure
void display( int n ) {
   printf( "The value is %d", n );
}
Run Code Online (Sandbox Code Playgroud)

虽然你应该注意C标准不讨论程序,只讨论函数.

  • 答案没有错,它是纯函数和过程之间差异的一个很好的例子.K&R将每个子程序称为"函数"以保持简单,但是具有副作用的子程序实际上是一个"程序",而不是数学规范意义上的"函数".如果将实际函数与过程区分开来,C可能是更好的语言,这有助于静态分析,性能优化和并行化. (6认同)
  • _... C标准不讨论程序,只讨论函数.这是因为它只有函数.一个什么都不返回的函数是一个`void function`.Kernighan&Ritchie Ch 1.7:"在C中,函数等同于Fortran中的子程序或函数,或Pascal中的过程或函数." 换句话说......这个答案是错误的. (4认同)

HS.*_*HS. 11

通常,过程是一系列指令.
函数可以相同,但通常返回结果.


sha*_*oth 10

有一个术语子程序子程序,它代表可以从不同位置调用的参数化代码段.

功能和程序是这些的实现.通常函数返回值和过程不返回任何内容.


小智 6

基本差异

  • Function必须返回一个值,但在Stored Procedures中它是可选的:一个过程可以返回0或n值.
  • 函数只能有输入参数,而过程可以有输入/输出参数.
  • 对于函数,必须采用一个输入参数,但存储过程可能需要0到n个输入参数.
  • 可以从过程调用函数,而无法从函数调用过程.

高级差异

  • 异常可以通过过程中的try-catch块来处理,而try-catch块不能在Function中使用.
  • 我们可以在一个过程中进行事务管理,而在一个函数中我们不能.

在SQL中:

  • 程序允许SELECT以及DML( ,INSERT,UPDATE)DELETE在其声明,而功能只允许SELECT声明它.
  • 程序不能在SELECT语句中使用,而函数可以嵌入SELECT语句中.
  • 存储过程不能在WHERE(或一个HAVING或多个SELECT)块中的任何位置的SQL语句中使用,而函数可以.
  • 返回表的函数可以视为另一个Rowset.这可以在JOIN与其他表的块中使用.
  • 内联函数可以被视为带参数的视图,可以在JOIN块和其他Rowset操作中使用.

  • 这个问题是针对特定语言的,而问题与语言无关。此处的陈述在一般情况下并不都是正确的,但是如果您弄清楚要为其声明的语言或环境,将很有帮助。 (2认同)

Ing*_*ngo 5

更严格的是,如果x = y,函数f服从f(x)= f(y)的属性,即每次用相同的参数调用它时计算相同的结果(因此它不会改变状态系统.)

因此,rand()或print("Hello")等不是函数而是程序.虽然sqrt(2.0)应该是一个函数:没有可观察到的效果或状态改变,无论多少次调用它,它总是返回1.41和一些.

  • 这种用法在"功能"编程的上下文中是相关的.请注意,调用其子程序"函数"的许多(通常是命令性的)语言不需要此属性. (3认同)
  • 我并不建议编程语言需要这个属性。不管怎样,人们可以用任何语言编写严格的函数,我觉得尽可能使用干净的函数进行编程,然后将各个部分与一些主要过程粘合在一起是一个好习惯。 (2认同)

Fra*_*kHB 5

这是一个众所周知的老问题,但我想分享一些关于现代编程语言研究和设计的更多见解。

基本答案

传统上(在结构化编程的意义上)和非正式地,过程是一种可重用的结构构造,具有“输入”并执行一些可编程的操作。当需要在过程中完成某事时,您可以在源代码中编码的过程调用中为过程提供(实际)参数(通常是一种表达式),以及在过程体中编码的动作(提供在过程的定义中)将通过将参数替换为主体中使用的(形式)参数来执行。

函数超过因为程序的返回值也可以被指定为在体内的“输出”。函数调用与过程调用或多或少相同,除了您还可以在语法上使用函数调用的结果(通常作为某个其他表达式的子表达式)。

传统上,过程调用(而不是函数调用)用于指示必须没有输出感兴趣,并且必须有副作用以避免调用是空操作,因此强调命令式编程范式。许多像 Pascal 这样的传统编程语言都提供了“过程”和“函数”来区分这种有意的风格差异。

(需要说明的是,上面提到的“输入”和“输出”是基于函数句法特性的简化概念。许多语言还支持通过引用/共享将参数传递给参数,以允许用户在调用过程中传输参数中编码的信息.这样的参数甚至可以被称为“输入/输出参数”。这个特性是基于调用中传递的对象的性质,它与过程/函数的特性的特性是正交的。)

但是,如果不需要函数调用的结果,则可以(至少在逻辑上)忽略它,并且函数定义/函数调用应该以这种方式与过程定义/过程调用保持一致。类似 ALGOL 的语言,如 C、C++ 和 Java,都以这种方式提供了“函数”的特性:通过将结果类型编码void为看起来像传统过程的函数的特例,不需要提供“过程”的特性。 “ 分别地。这可以防止语言设计中的一些膨胀。

既然提到了SICP,那么还值得注意的是,在R n RS指定的Scheme 语言中,一个过程可能需要也可能不需要返回计算结果。这是传统“函数”(返回结果)和“过程”(不返回任何内容)的结合,本质上与许多类似 ALGOL 的语言的“函数”概念相同(实际上共享更多保证,例如对调用前的操作数)。然而,即使在像SRFI-96这样的规范性文件中,老式的差异仍然存在。

我对分歧背后的确切原因知之甚少,但正如我所经历的那样,现在似乎没有规范膨胀的语言设计者会更快乐。也就是说,作为独立功能的“过程”是不必要的。像void类型这样的技术已经足以标记应该强调副作用的用途。这对于具有类似 C 语言经验的用户来说也更自然,这些语言已经流行了几十年。此外,它避免了像 R n RS这样的尴尬,在这种情况下,“过程”实际上是更广泛意义上的“功能”。

理论上,一个函数可以指定一个指定的单元类型作为函数调用结果的类型,以表明该结果是特殊的。这将传统程序(对调用结果不感兴趣)与其他程序区分开来。语言的设计有不同的风格:

  • 就像在 R n RS 中一样,只需将不感兴趣的结果标记为“未指定”值(未指定类型,如果语言必须提及它)并且可以忽略它就足够了。
  • 将不感兴趣的结果指定为专用单元类型(例如Kernel#inert)的值也有效。
  • 当该类型是进一步的底部类型时,它可以(希望)静态验证并防止用作表达式类型。voidALGOL 类语言中的类型正是这种技术的一个例子。ISO C11_Noreturn是一种类似但更微妙的类型。

进一步阅读

作为源自数学的传统概念,有很多大多数人都懒得知道的黑魔法。严格来说,你不太可能按照你的数学书把事情搞清楚。CS 书籍也可能不会提供太多帮助。

关于编程语言,有几个注意事项:

  • 数学不同分支中的函数并不总是具有相同的含义。不同编程范式中的函数也可能完全不同(甚至有时函数调用的语法看起来很相似)。有时导致差异的原因是相同的,但有时则不同。
    • 这是惯用的数学函数模型计算,然后实现底层的编程语言的计算。除非您知道正在谈论的内容,否则请小心避免将它们一对一地映射。
  • 不要将模型与要建模的实体混淆。
  • 在数学上,函数可以是partialtotal。不同的编程语言在这里有不同的处理方式。
    • 一些函数式语言可能尊重函数的整体性,以保证函数调用中的计算总是在有限的步骤中终止。然而,这本质上不是图灵完备的,因此计算表达能力较弱,除了类型检查的语义(预计是全部的)之外,在通用语言中也很少见。
    • 如果程序和功能之间的差异很大,是否应该有“总程序”?唔...
  • 构建在用于结石类似的功能,一般的计算模型编程语言的语义(如拉姆达抽象的拉姆达结石)可以有不同的评估策略上的操作数。
    • 在传统的纯微积分的减少以及纯函数式语言中表达式的评估中,没有改变计算结果的副作用。因此,不需要在类似函数的构造体之前评估操作数(因为定义“相同结果”的不变量由Church-Rosser 属性保证的? -等价性等属性保持)。
    • 但是,许多编程语言在表达式求值过程中可能会产生副作用。这意味着,像应用评估这样的严格评估策略与像call-by-need这样的非严格评估策略是不同的。这很重要,因为如果没有区别,就没有必要将类似函数的(即与参数一起使用的)宏与(传统的)函数区分开来。但根据理论的风格,这仍然可能是一个神器。也就是说,在更广泛的意义上,类似函数的宏(尤其是卫生宏)具有一些不必要限制(句法阶段)的数学函数。没有这些限制,将(一流的)类函数宏视为过程可能是明智的......
    • 对于对此主题感兴趣的读者,请考虑一些现代抽象
  • 程序通常被认为超出了传统数学的范围。然而,在计算和编程语言语义的演算建模以及当代编程语言设计中,可能有相当大的相关概念家族共享“可调用”性质。其中一些用于实现/扩展/替换过程/功能。还有更细微的区别。