“功能”和“程序”之间有什么区别?


203

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

所以,我的问题是:

在功能,目的和用途上有什么区别?

一个例子将不胜感激。



6
我认为SICP正确。函数仅存在于数学中,它们代表着什么是知识。程序以编程语言(包括功能性语言)存在,它们代表了如何知识。函数:sqrt(x)= y,使得y ^ 2 = x。程序(define (sqrt x) (newtons-method (lambda (y) (- (square y) x)) 1.0))
mk12

Answers:


295

一个函数返回一个值,而一个过程仅执行命令。

名称函数来自数学。用于基于输入来计算值。

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

在大多数编程语言中,甚至函数也可以具有一组命令。因此,区别仅在于返回值部分。

但是,如果您希望保持函数整洁(只需看一下函数语言),就需要确保函数没有副作用。


如何保证命令式(java,c)或声明性语言(scala,scheme)不会产生副作用?
orlybg

1
@orlybg,在声明性语言中,一致性来自该语言的实现。它们的范围限制可防止它们产生副作用。另一方面,命令式语言明确地利用了它们的副作用。副作用并不总是坏的。
Tharindu Rusira

我正在阅读以下Ada教程(goanna.cs.rmit.edu.au/~dale/ada/aln/8_subprograms.html),该页面的第二段以“ Ada中的过程与Pascal中的过程相似一个过程可以包含return语句。” 这是文字错误吗?还是意味着它可以具有return语句但不返回任何值?
jviotti 2015年

3
在pascal中,过程没有return语句,只有函数有。文本中必须有错误。但是,过程可以具有“退出”语句,该语句可以充当不带参数的“返回”语句,这意味着没有返回值。
埃里克·福捷

函数可以获取输入,仅返回输出。过程或宏可以获取输入并且不返回任何数据,仅执行多个语句即可。主要区别在于过程无法返回任何数据类型。
EsmaeelE

42

这取决于上下文。

在类似Pascal的语言中,函数和过程是不同的实体,不同之处在于它们是否返回值。他们的行为不同。语言语法(例如,过程调用表单语句;您不能在表达式内部使用过程调用,而函数调用则不能在表单语句中使用,您必须在其他语句中使用它们)。因此,帕斯卡(Pascal)的程序员可以区分这些。

在类似C的语言和许多其他当代语言中,这种区别消失了。在静态类型语言中,过程只是具有有趣返回类型的函数。这可能就是为什么它们可以互换使用的原因。

在函数式语言中,通常没有诸如过程之类的东西-一切都是函数。


编程语言的文档和文档可以调用任何喜欢的函数和过程,因为人们很容易接受任何名称,因为这些名称背后的背景早就被淘汰了。
Arne Babenhauserheide 2015年

18

在C中的示例:

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

// procedure
void display( int n ) {
   printf( "The value is %d", n );
}

尽管您应该注意,C标准并未讨论过程,但仅涉及函数。


4
... C标准不讨论程序,只讨论功能。那是因为它仅具有功能。不返回任何内容的函数是void function。Kernighan&Ritchie Ch 1.7:“在C语言中,函数等效于Fortran中的子例程或函数,或者在Pascal中等效于过程或函数。” 换句话说...这个答案是错误的。
Mogsdad

8
答案是正确的,它是纯函数和过程之间差异的一个很好的例子。K&R称每个子程序为使事情简单的“函数”,但实际上,具有副作用的子程序是“过程”,而不是数学意义上的“函数”。如果C将实际函数与过程区分开,则C可能是更好的语言,这将有助于进行静态分析,性能优化和并行化。
山姆·沃特金斯2015年

12

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


11

有一个术语子例程子程序,代表可以在不同地方调用的参数化代码段。

功能和过程就是这些的实现。通常,函数返回值,而过程则不返回任何东西。


6

基本差异

  • 函数必须返回一个值,但是在存储过程中它是可选的:过程可以返回0或n个值。
  • 函数只能具有输入参数,而过程可以具有输入/输出参数。
  • 对于功能,必须采用一个输入参数,但是存储过程可能采用0到n个输入参数。
  • 可以从过程中调用函数,而不能从函数中调用过程。

高级差异

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

在SQL中:

  • 程序允许SELECT以及DML( ,INSERTUPDATE),DELETE则它的语句,而功能只允许SELECT声明它。
  • 过程不能在SELECT语句中使用,而函数可以嵌入在SELECT语句中。
  • WHERE(或a HAVING或a SELECT)块中的任何地方,都不能在SQL语句中使用存储过程,而可以使用函数。
  • 返回表的函数可以视为另一个行集。可以在JOIN其他表的块中使用。
  • 内联函数可以认为是带有参数的视图,可以在JOIN块和其他行集操作中使用。

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

5

更严格地讲,如果x = y,则函数f服从f(x)= f(y)的属性,即,每次使用相同的参数调用该函数时,它都会计算出相同的结果(因此,该函数不会更改其状态)。系统。)

因此,rand()或print(“ Hello”)等不是函数,而是过程。虽然sqrt(2.0)应该是一个函数:不管有多少次调用它,都不会产生明显的效果或状态变化,并且总是返回1.41和某些值。


3
在“功能”编程的上下文中避免了这种用法。请注意,许多将其子程序称为“函数”的语言(通常是命令性语言)不需要此属性。
dmckee ---前主持人小猫,

1
我不建议编程语言需要此属性。无论如何,一个人可以用任何一种语言编写严格的函数,我觉得这是一个好习惯,即尽可能多地使用干净的函数进行编程,然后将其与某些主要过程粘合在一起。
Ingo 2009年

4

如果我们在这里与语言无关,那么过程通常会指定一系列操作,这些操作需要可靠且幂等地实现某些结果。即,过程基本上是算法。

另一方面,函数是较大程序中有点独立的代码。换句话说,功能是程序的实现。


4

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

基本答案

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

函数超过因为程序的返回值也可以被指定为在体内的“输出”。函数调用与过程调用大致相同,不同之处在于,您还可以在语法上使用函数调用的结果(通常用作其他表达式的子表达式)。

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

(显然,上述“输入”和“输出”是基于函数的语法属性的简化概念。许多语言还支持通过引用/共享将参数传递给参数,以允许用户在调用过程中传输以参数编码的信息该参数甚至可以称为“输入/输出参数”。此功能基于调用中传递的对象的性质,该性质与过程/功能的特征的属性正交。)

但是,如果不需要函数调用的结果,则可以(至少在逻辑上)忽略它,并且函数定义/函数调用应以这种方式与过程定义/过程调用一致。类似于C,C ++和Java的类似于ALGOL的语言都以这种方式提供“函数”的功能:通过将结果类型编码void为类似于传统过程的函数的特例,无需提供“过程”功能”。这样可以防止语言设计出现膨胀。

由于提到了SICP,因此还值得注意的是,在R n RS指定的方案语言中,过程可能必须也可能不必返回计算结果。这是传统的“函数”(返回结果)和“过程”(不返回任何结果)的结合,与许多类似ALGOL的语言的“函数”概念基本相同(并且实际上共享了更多的保证,例如对应用程序的评估)。调用前的操作数)。但是,即使在诸如SRFI-96之类的规范性文件中,仍会出现旧式差异。

我对这种差异背后的确切原因并不十分了解,但是据我所知,如今的语言设计师似乎会更加高兴,而不会出现规范膨胀。即,不需要“程序”作为独立功能。诸如voidtype之类的技术已经足以标记应强调副作用的用途。对于拥有数十年来流行的类C语言经验的用户来说,这也更为自然。而且,它避免了像R n RS这样的情况下的尴尬,在这种情况下,“过程”实际上是广义上的“功能”。

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

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

进一步阅读

作为从数学派生的传统概念,大多数人不介意知道大量的黑魔法。严格来说,按照数学书籍,您不太可能将所有事情弄清楚。CS书籍也可能没有太大帮助。

关于编程语言,有一些警告:

  • 数学的不同分支中的函数并非总是定义为具有相同的含义。不同编程范例中的函数也可能完全不同(甚至有时函数调用的语法看起来相似)。有时导致差异的原因是相同的,但有时并非如此。
    • 这是惯用的数学函数模型计算,然后实现底层的编程语言的计算。除非您知道所讨论的内容,否则请避免将它们一对一地映射。
  • 不要将模型与要建模的实体混淆。
  • 在数学上,功能可以是部分全部。不同的编程语言在这里有不同的处理方式。
    • 某些函数式语言可能会尊重函数的总数,以确保函数调用内的计算始终以有限的步长终止。但是,这本质上不是图灵完备的,因此计算表达能力较弱,并且在通用语言中除了类型检查的语义(预计将是总计)之外,很少见。
    • 如果程序和功能之间的差异很大,是否应该有“全部程序”?嗯...
  • 类似于用于计算通用计算演算语言的语义(例如lambda calculi中的lambda抽象)的演算中的函数的构造可以对操作数具有不同的评估策略
    • 在传统上,纯结石的减少以及纯函数语言中表达式的评估都没有副作用,不会改变计算结果。结果,不需要在类似函数的构造体之前对操作数进行求值(因为定义不变的“相同结果”由诸如Church-Rosser属性所保证的β等效性之类的属性所保持)。
    • 但是,许多编程语言在表达式求值过程中可能会有副作用。这意味着严格的评估策略(如应用评估)与非严格的评估策略(如按需呼叫)不同。这是很重要的,因为没有区别,就无需将类似于函数的宏(即与自变量一起使用)与(传统)函数区分开。但是根据理论的风格,这仍然可能是人工制品。也就是说,从广义上讲,类似函数的宏(尤其是卫生的宏)数学函数,具有一些不必要的限制(语法阶段)。没有限制,将(一流的)类函数宏视为过程可能是理智的。
    • 对于对此主题感兴趣的读者,请考虑一些现代抽象
  • 程序通常被认为超出了传统数学的范围。但是,在计算计算和编程语言语义以及当代编程语言设计的演算建模中,可能会有相当多的相关概念家族共享“可调用”性质。其中一些用于实现/扩展/替换过程/功能。还有更细微的区别。
    • 这里是一些相关的关键字:子例程 /(无堆栈/堆栈)协程 /(无界分隔)延续 ...甚至(未检查的)异常

3

在大多数情况下:函数返回一个值,而过程则不返回。两者都是组合在一起以执行相同操作的代码。

在函数式编程上下文中(所有函数均返回值),函数是抽象对象:

f(x)=(1+x)
g(x)=.5*(2+x/2)

在这里,f与g是相同的函数,但是是不同的过程。


3

内部过程中,我们可以使用DML(Insert / Update / Delete)语句,但是内部函数中,我们不能使用DML语句。

过程可以同时具有输入\输出参数,但是功能只能具有输入参数。

我们可以在存储过程中使用Try-Catch块,但是在功能上我们不能使用Try-Catch块。

我们不能在Select语句中使用存储过程,但是在函数中我们可以在Select语句中使用。

存储过程可以返回0或n个值(最大1024个),但是函数只能返回1个强制性值。

不能从Function调用存储过程,但是我们可以从Stored Procedure调用函数。

我们可以在存储过程中使用事务,但是在函数中我们不能使用事务。

我们无法在Where / Having / select部分的任何地方使用Sql语句中的存储过程,但可以使用In函数。

我们不能加入存储过程,但是我们可以加入函数。

有关更多..请单击此处... http://dotnet-developers-cafe.blogspot.in/2013/08/difference-between-stored-procedure-and.html


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

对于大多数编程语言,此答案是完全错误的。过程仅具有输入参数,而函数同时具有输入和输出。
AStopher '16

2

一个函数返回一个值,而一个过程仅执行命令。

名称函数来自数学。用于基于输入来计算值。

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

在大多数编程语言中,甚至函数也可以具有一组命令。因此,区别仅在于返回值部分。

但是,如果您希望保持函数整洁(只需看一下函数语言),就需要确保函数没有副作用。


1

函数可以在sql语句中使用,而过程不能在sql语句中使用。

插入,更新和创建语句不能包含在函数中,但是过程可以包含这些语句。

过程支持事务,但功能不支持事务。

函数必须返回一个且只有一个值(另一个可以由OUT变量返回),但是过程将返回尽可能多的数据集和返回值。

函数和过程的执行计划都被缓存,因此两种情况下的性能都相同。


1

在大多数答案中,我不停地反复看到一些东西,那就是使函数成为函数的原因是它返回一个值。

函数不仅仅是返回值的任何旧方法。并非如此:为了使方法成为实函数,它必须始终在给定特定输入的情况下返回相同的值。不是函数的方法的一个示例是random方法的大多数语言中方法,因为尽管它确实返回一个值,但该值并不总是相同的。

因此,函数更类似于地图(例如,x -> x'一维函数在哪里)。这是常规方法与函数之间的一个非常重要的区别,因为在处理实函数时,对它们的时间安排和评估顺序应该无关紧要,因为非函数并不总是这样。

这是不是函数的方法的另一个示例,但该方法仍将返回值。

// The following is pseudo code:
g(x) = {
  if (morning()) {
     g = 2 * x;
  }
  else {
   g = x;
  }
  return g;
}

我进一步反对过程不返回值的观点。过程只是讨论函数或方法的一种特定方式。因此,这意味着如果您的过程定义或实现的基础方法返回一个值,那么请猜测该过程将返回一个值。以SICP中的以下代码段为例

// We can immediately translate this definition into a recursive procedure 
// for computing Fibonacci numbers:

(define (fib n)
  (cond ((= n 0) 0)
        ((= n 1) 1)
        (else (+ (fib (- n 1))
                 (fib (- n 2))))))

您最近是否听说过递归程序?他们在谈论递归函数(一个实函数),并且正在返回一个值,并且他们使用的是“过程”一词。那有什么区别呢?

关于函数的另一种思考方式(除上述含义之外)是作为诸如数字1的理想的抽象表示。过程是该事物的实际实现。我个人认为它们是可以互换的。

(请注意,如果您从我提供的链接中阅读了该章,您可能会发现,要理解一个较难的概念不是函数和过程之间的区别,而是过程和过程之间的区别。您知道递归过程可以具有迭代过程?)

程序的类似物是配方。例如; 假设您有一台名为make-pies该机器的机器,该机器接受的成分,(fruit, milk, flower, eggs, sugar, heat)并且该机器返回pie

这台机器的表示可能看起来像

make-pies (fruit, milk, flower, eggs, sugar, heat) = {
   return (heat (add fruit (mix eggs flower milk)))
}

当然,这不是做馅饼的唯一方法。

在这种情况下,我们可以看到:

A       function     is to a     machine
as a    procedure    is to a     recipe
as      attributes   are to      ingredients
as      output       is to       product

这样的类比是可以的,但是当您考虑到处理计算机程序时,所有东西都是抽象的,因此它可以分解。因此,与在机器上使用配方不同的是,我们正在比较本身就是抽象的两件事。两件事可能是同一件事。我认为,它们(出于所有意图和目的)都是同一件事。


2
对于给定的参数始终返回相同值的函数有时称为“纯函数”。在大多数区分过程和函数的语言中,函数不一定是纯函数,术语“函数”正确地用于指代可能具有副作用并且可以在使用相同参数的连续调用中返回不同结果的子例程。(在类似C的语言中,即使不返回值的子例程也被正确地称为“函数”。)
Keith Thompson

同意,这就是为什么我在结束时说这两个词可以互换。
dkinzer 2014年

1
是的,但是您首先要说“一个函数不仅仅是返回值的任何旧方法”,而在许多语言中,这恰恰是一个函数。
基思·汤普森

0

db上下文中:存储过程是预编译的执行计划,而as函数则没有。


0

就С#/ Java而言,函数是返回特定值的代码块,而过程是返回void(无)的代码块。在C#/ Java中,函数和过程都更常称为正义方法

    //This is a function
    public DateTime GetCurrentDate()
    {
        return DateTime.Now.Date;
    }

    //This is a procedure(always return void)
    public void LogMessage()
    {
        Console.WriteLine("Just an example message.");
    }

-3

过程:1. 过程是定义参数化计算的语句的集合。2.过程不能返回值。

3.无法从函数调用过程。

函数 1. 函数在结构上类似于过程,但在语义上基于数学函数建模。2.它可以返回值。3.可以从程序中调用函数。


3.无法从函数调用过程。用什么语言是真的?我没有经验的人对此有限制。
Mogsdad

是真的。如果从函数调用过程,则它不是函数。至于用什么语言来实现这一点,这是一个很好的问题,我不知道答案。可能是功能性的,但是即使那样我也不确定:纯列表是功能性的(没有集合:没有副作用),但是由于它具有lambda,因此可以实现集合。您能否编写不强制使用set的编译器,就必须检测它的所有实现。您可以从该语言中删除lambda,但这会更糟。
ctrl-alt-delor

喔我只是觉得一个语言C ++的:一个const方法不能调用没有const的方法(虽然你需要打开正确的编译器检查,而不是试图很难去了解它。)
CTRL-ALT-delor

-7

过程和函数都是子例程,它们之间的唯一区别是过程返回多个(或至少可以做到)值,而函数只能返回一个值(这就是为什么在数学中使用函数表示法的原因,因为通常只找到一个值在某一特定时间)尽管某些编程语言未遵循这些规则,但这是它们的真实定义


不。一个过程return什么都没有。您正在谈论的是副作用,两者都可能发生(如果语言允许)。
Mogsdad

一个过程可以返回任意数量的值,该数量可以为零
user2766296

副作用是,如果一个数组具有一个数组并将其传递到找到最大值的函数或过程中,则该数组将通过引用传递,并且在子例程运行后对数组进行排序,事实是sorted是一个副作用,返回的值是数组中的
最大值

我喜欢这个答案,也喜欢那些投票数不多的人,因为从某种意义上来说是很正确的,因此,自相矛盾的是,为了使其在SO中非常受欢迎,我将其给予投票。SQL Server中的存储过程返回一个结果集(您称为“多个值”),而一个函数只能返回一个值(由于您还可以创建一个表值函数,因此它不是很准确)。
伊万津尼奥(Ivanzinho),
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.