Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 5 years ago.
The community reviewed whether to reopen this question last year and left it closed:
Original close reason(s) were not resolved
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
接受
或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
发布评论
评论(17)
过程语言倾向于跟踪状态(使用变量)并倾向于作为一系列步骤执行。 纯函数式语言不跟踪状态,使用不可变值,并且倾向于作为一系列依赖项执行。 在许多情况下,调用堆栈的状态将保存与存储在过程代码中的状态变量中的信息等效的信息。
递归是函数式编程的经典示例。
Procedural languages tend to keep track of state (using variables) and tend to execute as a sequence of steps. Purely functional languages don't keep track of state, use immutable values, and tend to execute as a series of dependencies. In many cases the status of the call stack will hold the information that would be equivalent to that which would be stored in state variables in procedural code.
Recursion is a classic example of functional style programming.
要理解其中的差异,我们需要了解过程式编程和函数式编程的“教父”范式是命令式编程。
基本上,过程式编程只是构造命令式程序的一种方式,其中主要的抽象方法是“过程”。 (或某些编程语言中的“函数”)。 即使面向对象编程也只是构造命令式程序的另一种方式,其中状态被封装在对象中,成为具有“当前状态”的对象,并且该对象具有一组函数、方法和其他东西,可以让您程序员操纵或更新状态。
现在,就函数式编程而言,其方法的要点是确定要采用哪些值以及如何传输这些值。 (因此没有状态,也没有可变数据,因为它将函数作为第一类值并将它们作为参数传递给其他函数)。
PS:了解每种编程范例的用途应该能够澄清它们之间的差异。
PSS:归根结底,编程范式只是解决问题的不同方法。
PSS:这个 quora 答案有很好的解释。
To Understand the difference, one needs to to understand that "the godfather" paradigm of both procedural and functional programming is the imperative programming.
Basically procedural programming is merely a way of structuring imperative programs in which the primary method of abstraction is the "procedure." (or "function" in some programming languages). Even Object Oriented Programming is just another way of structuring an imperative program, where the state is encapsulated in objects, becoming an object with a "current state," plus this object has a set of functions, methods, and other stuff that let you the programmer manipulate or update the state.
Now, in regards to functional programming, the gist in its approach is that it identifies what values to take and how these values should be transferred. (so there is no state, and no mutable data as it takes functions as first class values and pass them as parameters to other functions).
PS: understanding every programming paradigm is used for should clarify the differences between all of them.
PSS: In the end of the day, programming paradigms are just different approaches to solving problems.
PSS: this quora answer has a great explanation.
扩展康拉德的评论:
一些函数式语言具有所谓的“惰性求值”。 这意味着函数在需要该值之前不会执行。 在那之前,函数本身就是被传递的。
过程语言是步骤 1 步骤 2 步骤 3...如果在步骤 2 中你说加 2 + 2,那么它就会正确执行。 在惰性计算中,您会说加 2 + 2,但如果从未使用结果,则它永远不会执行加法。
To expand on Konrad's comment:
Some functional languages have what is called Lazy Evaluation. Which means a function is not executed until the value is needed. Until that time the function itself is what is passed around.
Procedural languages are step 1 step 2 step 3... if in step 2 you say add 2 + 2, it does it right then. In lazy evaluation you would say add 2 + 2, but if the result is never used, it never does the addition.
康拉德说:
纯函数式程序中的求值顺序可能很难(呃)推理(尤其是因为懒惰),甚至不重要,但我认为说它没有很好地定义会让听起来你无法判断你的程序是否正在运行根本不去工作!
也许更好的解释是函数式程序中的控制流基于何时需要函数参数的值。 这样做的好处是,在编写良好的程序中,状态变得明确:每个函数都将其输入列为参数,而不是任意 修改全局状态。 因此,在某种程度上,更容易推断一次针对一个函数的求值顺序。 每个功能都可以忽略宇宙的其余部分并专注于它需要做的事情。 组合后,函数保证与单独运行时的工作方式相同[1]。
纯函数式程序中输入问题的解决方案是使用 DSL 嵌入命令式语言a href="http://en.wikipedia.org/wiki/Monads_in_function_programming" rel="noreferrer">足够强大的抽象。 在命令式(或非纯函数式)语言中,这是不需要的,因为您可以“作弊”并隐式传递状态,并且评估顺序是明确的(无论您是否喜欢)。 由于这种“作弊”和对每个函数的所有参数的强制评估,在命令式语言中 1)您失去了创建自己的控制流机制(没有宏)的能力,2)代码本质上不是线程安全的和/或可并行的默认情况下,3)并实现诸如撤消(时间旅行)之类的东西需要仔细工作(命令式程序员必须存储恢复旧值的方法!),而纯函数式编程则可以为您带来一切这些东西——还有一些我可能已经忘记了——“免费”。
我希望这听起来不像狂热,我只是想添加一些观点。 命令式编程,尤其是 C# 3.0 等强大语言中的混合范式编程仍然是完成任务的完全有效的方法,并且有没有灵丹妙药。
[1] ...除非可能与内存使用有关(参见 Haskell 中的 Foldl 和 Foldl')。
Konrad said:
The order of evaluation in a purely functional program may be hard(er) to reason about (especially with laziness) or even unimportant but I think that saying it is not well defined makes it sound like you can't tell if your program is going to work at all!
Perhaps a better explanation would be that control flow in functional programs is based on when the value of a function's arguments are needed. The Good Thing about this that in well written programs, state becomes explicit: each function lists its inputs as parameters instead of arbitrarily munging global state. So on some level, it is easier to reason about order of evaluation with respect to one function at a time. Each function can ignore the rest of the universe and focus on what it needs to do. When combined, functions are guaranteed to work the same[1] as they would in isolation.
The solution to the input problem in purely functional programs is to embed an imperative language as a DSL using a sufficiently powerful abstraction. In imperative (or non-pure functional) languages this is not needed because you can "cheat" and pass state implicitly and order of evaluation is explicit (whether you like it or not). Because of this "cheating" and forced evaluation of all parameters to every function, in imperative languages 1) you lose the ability to create your own control flow mechanisms (without macros), 2) code isn't inherently thread safe and/or parallelizable by default, 3) and implementing something like undo (time travel) takes careful work (imperative programmer must store a recipe for getting the old value(s) back!), whereas pure functional programming buys you all these things—and a few more I may have forgotten—"for free".
I hope this doesn't sound like zealotry, I just wanted to add some perspective. Imperative programming and especially mixed paradigm programming in powerful languages like C# 3.0 are still totally effective ways to get things done and there is no silver bullet.
[1] ... except possibly with respect memory usage (cf. foldl and foldl' in Haskell).
如果你有机会,我建议你获取一份 Lisp/Scheme 的副本,并在其中做一些项目。 最近成为潮流的大多数想法都是几十年前在 Lisp 中表达的:函数式编程、延续(作为闭包)、垃圾收集,甚至 XML。
因此,这将是一个很好的方法,可以让我们在所有这些当前的想法以及其他一些想法(例如符号计算)方面取得先机。
您应该知道函数式编程有什么好处,有什么坏处。 这并不对一切都有好处。 有些问题最好用副作用来表达,即同一问题根据何时提出而给出不同的答案。
If you have a chance, I would recommand getting a copy of Lisp/Scheme, and doing some projects in it. Most of the ideas that have lately become bandwagons were expressed in Lisp decades ago: functional programming, continuations (as closures), garbage collection, even XML.
So that would be a good way to get a head start on all these current ideas, and a few more besides, like symbolic computation.
You should know what functional programming is good for, and what it isn't good for. It isn't good for everything. Some problems are best expressed in terms of side-effects, where the same question gives differet answers depending on when it is asked.
函数式编程与过程式编程相同,其中不使用全局变量。
A functional programming is identical to procedural programming in which global variables are not being used.
这里的答案都没有显示惯用的函数式编程。 递归阶乘答案非常适合表示 FP 中的递归,但大多数代码不是递归的,所以我认为这个答案不完全具有代表性。
假设您有一个字符串数组,每个字符串代表一个整数,例如“5”或“-200”。 您想要根据内部测试用例检查此输入字符串数组(使用整数比较)。 两种解决方案如下所示。
过程
函数
虽然纯函数语言通常是研究语言(因为现实世界喜欢免费的副作用),但现实世界的过程语言将在适当的时候使用更简单的函数语法。
这通常通过 Lodash 等外部库来实现,或者使用更新的内置库来实现像 Rust 这样的语言。 函数式编程的繁重工作是通过诸如
map
、filter
、reduce
、currying
、< code>partial,最后三个你可以查阅以进一步了解。附录
为了在野外使用,编译器通常必须弄清楚如何在内部将函数版本转换为过程版本,因为函数调用开销太高。 递归情况(例如所示的阶乘)将使用 尾调用 等技巧来删除 O(n)内存使用情况。 没有副作用的事实允许函数编译器实现
&& 即使
优化。 在 JS 中使用 Lodash 显然不允许进行任何优化,因此它会影响性能(这通常不是 Web 开发的问题)。 像 Rust 这样的语言会在内部进行优化(并且有诸如.reduce
最后完成,也会进行 rettry_fold
之类的函数来辅助&& ret
优化)。None of the answers here show idiomatic functional programming. The recursive factorial answer is great for representing recursion in FP, but the majority of code is not recursive so I don't think that answer is fully representative.
Say you have an arrays of strings, and each string represents an integer like "5" or "-200". You want to check this input array of strings against your internal test case (Using integer comparison). Both solutions are shown below
Procedural
Functional
While pure functional languages are generally research languages (As the real-world likes free side-effects), real-world procedural languages will use the much simpler functional syntax when appropriate.
This is usually implemented with an external library like Lodash, or available built-in with newer languages like Rust. The heavy lifting of functional programming is done with functions/concepts like
map
,filter
,reduce
,currying
,partial
, the last three of which you can look up for further understanding.Addendum
In order to be used in the wild, the compiler will normally have to work out how to convert the functional version into the procedural version internally, as function call overhead is too high. Recursive cases such as the factorial shown will use tricks such as tail call to remove O(n) memory usage. The fact that there are no side effects allows functional compilers to implement the
&& ret
optimization even when the.reduce
is done last. Using Lodash in JS, obviously does not allow for any optimization, so it is a hit to performance (Which isn't usually a concern with web development). Languages like Rust will optimize internally (And have functions such astry_fold
to assist&& ret
optimization).过程式编程将语句序列和条件构造划分为称为过程的单独块,这些块通过作为(非函数)值的参数进行参数化。
函数式编程是相同的,只是函数是一等值,因此它们可以作为参数传递给其他函数并作为函数调用的结果返回。
请注意,在此解释中,函数式编程是过程式编程的概括。 然而,少数人将“函数式编程”解释为无副作用,这与除 Haskell 之外的所有主要函数式语言有很大不同但无关。
Procedural programming divides sequences of statements and conditional constructs into separate blocks called procedures that are parameterized over arguments that are (non-functional) values.
Functional programming is the same except that functions are first-class values, so they can be passed as arguments to other functions and returned as results from function calls.
Note that functional programming is a generalization of procedural programming in this interpretation. However, a minority interpret "functional programming" to mean side-effect-free which is quite different but irrelevant for all major functional languages except Haskell.
@Creighton:
在Haskell中有一个名为product的库函数:
或者简单地说:
所以“惯用的”阶乘
就是
@Creighton:
In Haskell there is a library function called product:
or simply:
so the "idiomatic" factorial
would simply be
我相信过程/函数/目标编程是关于如何解决问题的。
第一种风格将所有事情分成步骤进行规划,并通过一次实施一个步骤(一个过程)来解决问题。 另一方面,函数式编程强调分而治之的方法,将问题分为子问题,然后解决每个子问题(创建一个函数来解决该子问题),并将结果组合起来创建整个问题的答案。 最后,客观编程将通过在计算机内部创建一个包含许多对象的迷你世界来模仿现实世界,每个对象都有(某种程度上)独特的特征,并与其他对象交互。 从这些互动中,结果就会显现出来。
每种编程风格都有其自身的优点和缺点。 因此,做诸如“纯编程”(即纯粹程序性的——顺便说一句,没有人这样做,这有点奇怪——或者纯粹函数式或纯粹客观性)之类的事情即使不是不可能,也是非常困难的,除了一些特别的基本问题旨在展示编程风格的优势(因此,我们称那些喜欢纯粹的人为“weenie”:D)。
然后,根据这些风格,我们设计了针对每种风格进行优化的编程语言。 例如,汇编就是程序性的。 好吧,大多数早期语言都是过程语言,不仅是 Asm,还有 C、Pascal(我听说还有 Fortran)。 然后,我们所有著名的Java都在客观学派中(实际上,Java和C#也属于一个名为“金钱导向”的类别,但这是另一个讨论的主题)。 Smalltalk也是一个目标。 在函数式学派中,我们会有“近乎函数式”(有些人认为它们不纯)的Lisp家族和ML家族以及许多“纯函数式”Haskell、Erlang等。顺便说一句,还有很多通用语言,例如Perl、Python ,鲁比。
I believe that procedural/functional/objective programming are about how to approach a problem.
The first style would plan everything in to steps, and solves the problem by implementing one step (a procedure) at a time. On the other hand, functional programming would emphasize the divide-and-conquer approach, where the problem is divided into sub-problem, then each sub-problem is solved (creating a function to solve that sub problem) and the results are combined to create the answer for the whole problem. Lastly, Objective programming would mimic the real world by create a mini-world inside the computer with many objects, each of which has a (somewhat) unique characteristics, and interacts with others. From those interactions the result would emerge.
Each style of programming has its own advantages and weaknesses. Hence, doing something such as "pure programming" (i.e. purely procedural - no one does this, by the way, which is kind of weird - or purely functional or purely objective) is very difficult, if not impossible, except some elementary problems specially designed to demonstrate the advantage of a programming style (hence, we call those who like pureness "weenie" :D).
Then, from those styles, we have programming languages that is designed to optimized for some each style. For example, Assembly is all about procedural. Okay, most early languages are procedural, not only Asm, like C, Pascal, (and Fortran, I heard). Then, we have all famous Java in objective school (Actually, Java and C# is also in a class called "money-oriented," but that is subject for another discussion). Also objective is Smalltalk. In functional school, we would have "nearly functional" (some considered them to be impure) Lisp family and ML family and many "purely functional" Haskell, Erlang, etc. By the way, there are many general languages such as Perl, Python, Ruby.
我在这里没有看到真正强调的一件事是,现代函数式语言(例如 Haskell)实际上更多地使用第一类函数来进行流控制,而不是显式递归。 您不需要像上面那样在 Haskell 中递归地定义阶乘。 我认为类似的东西
是一个完全惯用的结构,并且在精神上更接近于使用循环而不是使用显式递归。
One thing I hadn't seen really emphasized here is that modern functional languages such as Haskell really more on first class functions for flow control than explicit recursion. You don't need to define factorial recursively in Haskell, as was done above. I think something like
is a perfectly idiomatic construction, and much closer in spirit to using a loop than to using explicit recursion.
扩展康拉德的评论:
因此,函数代码通常更容易并行化。 由于函数(通常)没有副作用,并且它们(通常)只是根据其参数进行操作,因此许多并发问题就消失了。
当您需要能够证明您的代码正确时,也可以使用函数式编程。 这对于过程式编程来说要困难得多(对于函数式编程来说不容易,但仍然更容易)。
免责声明:我已经很多年没有使用函数式编程了,直到最近才开始重新审视它,所以我在这里可能不完全正确。 :)
To expand on Konrad's comment:
Because of this, functional code is generally easier to parallelize. Since there are (generally) no side effects of the functions, and they (generally) just act on their arguments, a lot of concurrency issues go away.
Functional programming is also used when you need to be capable of proving your code is correct. This is much harder to do with procedural programming (not easy with functional, but still easier).
Disclaimer: I haven't used functional programming in years, and only recently started looking at it again, so I might not be completely correct here. :)
函数式编程
过程式编程
function_to_add_one
是一个函数procedure_to_add_one
是一个过程即使您运行该函数五次,每次都会返回 2
如果您运行该程序五次,则在第五次运行结束时,它将为您提供6。
表达式与语句
正如您在上面的代码中所看到的,在给定相同输入的情况下,函数始终计算出相同的输出。 由于它们评估为一个值,因此用技术术语来说它们是表达式。
另一方面,过程不会求值,它们可能不会返回任何内容,只是更改内部状态,因此它们不是表达式而是语句。
看完这些例子后,Omnimike的答案会更容易理解。
免责声明:显然,这是对现实的高度简化的看法。 这个答案只是给出了“功能”而不是“过程”的味道。 而已。 一旦你尝到了这种肤浅却又深刻的直觉,开始探索这两种范式,你就会开始非常清楚地看到差异。
对我的学生有帮助,希望对你也有帮助。
Funtional Programming
Procedural Programming
function_to_add_one
is a functionprocedure_to_add_one
is a procedureEven if you run the function five times, every time it will return 2
If you run the procedure five times, at the end of fifth run it will give you 6.
Expressions vs Statements
As you can see in the code above, functions always evaluate to the same output given the same input. And since they evaluate to a value, in technical terms they are expressions.
On the other hand, procedures don't evaluate to a value, they might not return anything, just change internal state and therefore they are NOT expressions but statements.
After seeing these examples, Omnimike's answer will be even easier to understand.
DISCLAIMER: Obviously this is a hyper-simplified view of reality. This answer just gives a taste of "functions" as opposed to "procedures". Nothing more. Once you have tasted this superficial yet deeply penetrative intuition, start exploring the two paradigms, and you will start to see the difference quite clearly.
Helps my students, hope it helps you too.
函数式语言(理想情况下)允许您编写数学函数,即采用n 个参数并返回一个值的函数。 如果程序被执行,则根据需要对该函数进行逻辑评估。1
另一方面,过程语言执行一系列顺序步骤。 (有一种将顺序逻辑转换为函数逻辑的方法,称为连续传递风格。)
因此,纯函数式程序对于输入总是产生相同的值,并且求值的顺序没有明确定义; 这意味着诸如用户输入或随机值之类的不确定值很难用纯函数语言进行建模。
1 与此答案中的其他所有内容一样,这是一个概括。 这种属性在需要结果时评估计算,而不是在调用时按顺序评估计算,称为“惰性”。 并非所有函数式语言实际上都是普遍惰性的,惰性也不只限于函数式编程。 相反,这里给出的描述提供了一个“心理框架”来思考不同的编程风格,这些风格不是截然不同和相反的类别,而是流动的想法。
A functional language (ideally) allows you to write a mathematical function, i.e. a function that takes n arguments and returns a value. If the program is executed, this function is logically evaluated as needed.1
A procedural language, on the other hand, performs a series of sequential steps. (There's a way of transforming sequential logic into functional logic called continuation passing style.)
As a consequence, a purely functional program always yields the same value for an input, and the order of evaluation is not well-defined; which means that uncertain values like user input or random values are hard to model in purely functional languages.
1 As everything else in this answer, that’s a generalisation. This property, evaluating a computation when its result is needed rather than sequentially where it’s called, is known as “laziness”. Not all functional languages are actually universally lazy, nor is laziness restricted to functional programming. Rather, the description given here provides a “mental framework” to think about different programming styles that are not distinct and opposite categories but rather fluid ideas.
我从未在其他地方看到过这个定义,但我认为这很好地总结了这里给出的差异:
函数式编程侧重于表达式
过程式编程的重点是语句
表达式具有值。 函数式程序是一种表达式,其值是计算机要执行的指令序列。
语句没有值,而是修改某些概念机器的状态。
在纯函数式语言中,不会有任何语句,因为无法操纵状态(它们可能仍然有一个名为“语句”的语法结构,但除非它操纵状态,否则我不会将其称为这个意义上的语句) )。 在纯粹的过程语言中,不会有任何表达式,一切都是操纵机器状态的指令。
Haskell 是纯函数式语言的一个例子,因为没有办法操纵状态。 机器代码是纯粹过程语言的一个例子,因为程序中的所有内容都是操纵机器寄存器和内存状态的语句。
令人困惑的部分是,绝大多数编程语言都包含表达式和语句,允许您混合范例。 根据语言鼓励使用语句与表达式的程度,可以将语言分为更具功能性或更具程序性。
例如,C 比 COBOL 更实用,因为函数调用是一个表达式,而在 COBOL 中调用子程序是一个语句(操作共享变量的状态并且不返回值)。 Python 比 C 更实用,因为它允许您使用短路求值将条件逻辑表达为表达式(test && path1 || path2 而不是 if 语句)。 Scheme 比 Python 更实用,因为 schema 中的所有内容都是一个表达式。
您仍然可以使用鼓励过程范式的语言以函数式风格进行编写,反之亦然。 只是以该语言不鼓励的范式编写会更困难和/或更尴尬。
I've never seen this definition given elsewhere, but I think this sums up the differences given here fairly well:
Functional programming focuses on expressions
Procedural programming focuses on statements
Expressions have values. A functional program is an expression who's value is a sequence of instructions for the computer to carry out.
Statements don't have values and instead modify the state of some conceptual machine.
In a purely functional language there would be no statements, in the sense that there's no way to manipulate state (they might still have a syntactic construct named "statement", but unless it manipulates state I wouldn't call it a statement in this sense). In a purely procedural language there would be no expressions, everything would be an instruction which manipulates the state of the machine.
Haskell would be an example of a purely functional language because there is no way to manipulate state. Machine code would be an example of a purely procedural language because everything in a program is a statement which manipulates the state of the registers and memory of the machine.
The confusing part is that the vast majority of programming languages contain both expressions and statements, allowing you to mix paradigms. Languages can be classified as more functional or more procedural based on how much they encourage the use of statements vs expressions.
For example, C would be more functional than COBOL because a function call is an expression, whereas calling a sub program in COBOL is a statement (that manipulates the state of shared variables and doesn't return a value). Python would be more functional than C because it allows you to express conditional logic as an expression using short circuit evaluation (test && path1 || path2 as opposed to if statements). Scheme would be more functional than Python because everything in scheme is an expression.
You can still write in a functional style in a language which encourages the procedural paradigm and vice versa. It's just harder and/or more awkward to write in a paradigm which isn't encouraged by the language.
基本上有两种风格,就像阴和阳。 一种是有组织的,另一种是混乱的。 在某些情况下,函数式编程是显而易见的选择,而在其他情况下,过程式编程是更好的选择。 这就是为什么至少有两种语言最近推出了包含两种编程风格的新版本。 ( Perl 6 和 D 2)
程序性:
Perl 6 < /a>
D 2
功能性:
Haskell
(复制自 维基百科 );
或一行:
Perl 6
D 2
旁注:
阶乘实际上是一个常见的示例,表明它是多么容易在 Perl 6 中创建新运算符的方式与创建子例程相同。 这个特性在 Perl 6 中根深蒂固,以至于 Rakudo 实现中的大多数运算符都是这样定义的。 它还允许您将自己的多个候选者添加到现有运算符中。
此示例还展示了范围创建 (
2..$n
) 以及与数字中缀结合的列表缩减元运算符 ([ OPERATOR ] LIST
)乘法运算符。 (<代码>*)它还表明您可以将
-->UInt
放在签名中,而不是在其后面添加returns UInt
。(您可以不用以
2
开始范围,因为在不带任何参数的情况下调用乘法“运算符”时将返回1
)Basically the two styles, are like Yin and Yang. One is organized, while the other chaotic. There are situations when Functional programming is the obvious choice, and other situations were Procedural programming is the better choice. This is why there are at least two languages that have recently come out with a new version, that embraces both programming styles. ( Perl 6 and D 2 )
Procedural:
Perl 6
D 2
Functional:
Haskell
( copied from Wikipedia );
or in one line:
Perl 6
D 2
Side note:
Factorial is actually a common example to show how easy it is to create new operators in Perl 6 the same way you would create a subroutine. This feature is so ingrained into Perl 6 that most operators in the Rakudo implementation are defined this way. It also allows you to add your own multi candidates to existing operators.
This example also shows range creation (
2..$n
) and the list reduction meta-operator ([ OPERATOR ] LIST
) combined with the numeric infix multiplication operator. (*
)It also shows that you can put
--> UInt
in the signature instead ofreturns UInt
after it.( You can get away with starting the range with
2
as the multiply "operator" will return1
when called without any arguments )在计算机科学中,函数式编程是一种将计算视为数学函数的评估并避免状态和可变数据的编程范式。 它强调函数的应用,与强调状态变化的过程式编程风格形成鲜明对比。
In computer science, functional programming is a programming paradigm that treats computation as the evaluation of mathematical functions and avoids state and mutable data. It emphasizes the application of functions, in contrast with the procedural programming style that emphasizes changes in state.