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

我的问题是:

它们的功能、目的和用途有什么不同?

请举例说明。


当前回答

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

3.不能从函数调用过程。

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

其他回答

C语言示例:

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

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

尽管你应该注意到C标准没有谈论过程,只有函数。

在С#/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.");
    }

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

在大多数情况下:函数返回一个值,而过程不返回。两者都是组合在一起做相同事情的代码片段。

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

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

这里,f和g是同一个函数,但是过程不同。

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

基本的答案

Traditionally (in the sense of structured programming) and informally, a procedure is a reusable structural construct to have "input" and to do something programmable. When something is needed to be done within a procedure, you can provide (actual) arguments to the procedure in a procedure call coded in the source code (usually in a kind of an expression), and the actions coded in the procedures body (provided in the definition of the procedure) will be executed with the substitution of the arguments into the (formal) parameters used in the body.

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

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

(To be clear, the "input" and "output" mentioned above are simplified notions based on the syntactic properties of functions. Many languages additionally support passing arguments to parameters by reference/sharing, to allow users transporting information encoded in arguments during the calls. Such parameter may even be just called as "in/out parameter". This feature is based on the nature of the objects being passed in the calls, which is orthogonal to the properties of the feature of procedure/function.)

However, if the result of a function call is not needed, it can be just (at least logically) ignored, and function definitions/function calls should be consistent to procedure definitions/procedure calls in this way. ALGOL-like languages like C, C++ and Java, all provide the feature of "function" in this fashion: by encoding the result type void as a special case of functions looking like traditional procedures, there is no need to provide the feature of "procedures" separately. This prevents some bloat in the language design.

Since SICP is mentioned, it is also worth noting that in the Scheme language specified by RnRS, a procedure may or may not have to return the result of the computation. This is the union of the traditional "function" (returning the result) and "procedure" (returning nothing), essentially same to the "function" concept of many ALGOL-like languages (and actually sharing even more guarantees like applicative evaluations of the operands before the call). However, old-fashion differences still occur even in normative documents like SRFI-96.

I don't know much about the exact reasons behind the divergence, but as I have experienced, it seems that language designers will be happier without specification bloat nowadays. That is, "procedure" as a standalone feature is unnecessary. Techniques like void type is already sufficient to mark the use where side effects should be emphasized. This is also more natural to users having experiences on C-like languages, which are popular more than a few decades. Moreover, it avoids the embarrassment in cases like RnRS where "procedures" are actually "functions" in the broader sense.

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

As in RnRS, just marking the uninterested results as "unspecified" value (of unspecified type, if the language has to mention it) and it is sufficient to be ignored. Specifying the uninterested result as the value of a dedicated unit type (e.g. Kernel's #inert) also works. When that type is a further a bottom type, it can be (hopefully) statically verified and prevented used as a type of expression. The void type in ALGOL-like languages is exactly an example of this technique. ISO C11's _Noreturn is a similar but more subtle one in this kind.

进一步的阅读

作为从数学中衍生出来的传统概念,有大量的黑魔法是大多数人都懒得知道的。严格地说,你不可能像你的数学书那样把所有事情都弄清楚。计算机科学书籍可能也提供不了太多帮助。

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

Functions in different branches of math are not always defined having same meanings. Functions in different programming paradigms may also be quite different (even sometimes the syntaxes of function call look similar). Sometimes the reasons to cause the differences are same, but sometimes they are not. It is idiomatic to model computation by mathematical functions and then implement the underlying computation in programming languages. Be careful to avoid mapping them one to one unless you know what are being talked about. Do not confuse the model with the entity be modeled. The latter is only one of the implementation to the former. There can be more than one choices, depending on the contexts (the branches of math interested, for example). In particular, it is more or less similarly absurd to treat "functions" as "mappings" or subsets of Cartesian products like to treat natural numbers as Von-Neumann encoding of ordinals (looking like a bunch of {{{}}, {}}...) besides some limited contexts. Mathematically, functions can be partial or total. Different programming languages have different treatment here. Some functional languages may honor totality of functions to guarantee the computation within the function calls always terminate in finite steps. However, this is essentially not Turing-complete, hence weaker computational expressiveness, and not much seen in general-purpose languages besides semantics of typechecking (which is expected to be total). If the difference between the procedures and functions is significant, should there be "total procedures"? Hmm... Constructs similar to functions in calculi used to model the general computation and the semantics of the programming languages (e.g. lambda abstractions in lambda calculi) can have different evaluation strategies on operands. In traditional the reductions in pure calculi as well in as evaluations of expressions in pure functional languages, there are no side effects altering the results of the computations. As a result, operands are not required to be evaluated before the body of the functions-like constructs (because the invariant to define "same results" is kept by properties like β-equivalence guaranteed by Church-Rosser property). However, many programming languages may have side effects during the evaluations of expressions. That means, strict evaluation strategies like applicative evaluation are not the same to non-strict evaluation ones like call-by-need. This is significant, because without the distinction, there is no need to distinguish function-like (i.e. used with arguments) macros from (traditional) functions. But depending on the flavor of theories, this still can be an artifact. That said, in a broader sense, functional-like macros (esp. hygienic ones) are mathematical functions with some unnecessary limitations (syntactic phases). Without the limitations, it might be sane to treat (first-class) function-like macros as procedures... For readers interested in this topic, consider some modern abstractions. Procedures are usually considered out of the scope of traditional math. However, in calculi modeling the computation and programming language semantics, as well as contemporary programming language designs, there can be quite a big family of related concepts sharing the "callable" nature. Some of them are used to implement/extend/replace procedures/functions. There are even more subtle distinctions. Here are some related keywords: subroutines/(stackless/stackful) coroutines/(undelimited delimited) continuations... and even (unchecked) exceptions.