编程范式 | 函数式编程与面向对象编程——差异、应用场景及正交性(篇 2)

注:本文为 "编程范式" 相关讨论译文合辑。

机翻未校,如有内容异常,请看原文。


[Functional Programming vs. OOP closed]

函数式编程与面向对象编程

I've heard a lot of talk about using functional languages such as Haskell as of late. What are some of the big differences, pros and cons of functional programming vs. object-oriented programming?

我最近经常听到关于使用 Haskell 等函数式语言的讨论。函数式编程与面向对象编程之间存在哪些显著差异、优势与劣势?

edited Nov 1, 2011 at 16:39

Adam Lear♦

asked Oct 5, 2010 at 19:02

GSto

One does not reject another.

两者并非相互排斥。

-- mbq

Commented Oct 5, 2010 at 19:27

@mbq i understand that they aren't mutually exclusive, but I just wanted to try to get a better understanding of the difference of the two approaches.

@mbq 我明白它们并非互斥关系,但我只是想更深入地理解这两种编程范式的差异。

-- GSto

Commented Oct 5, 2010 at 19:52

Great question. I've been wondering about this too.

这个问题问得很好,我也一直有这样的疑惑。

-- JohnFx

Commented Oct 5, 2010 at 20:57

Functional programming and object-oriented programming are orthogonal to each other. You can have both in the same language. Examples: Scala, F#, OCaml etc. Maybe you meant functional vs imperative, as Jonas suggested?

函数式编程与面向对象编程是相互正交的概念,二者可以共存于同一种编程语言中。例如 Scala、F#、OCaml 等语言均支持两种范式。或许你想提问的是函数式编程与命令式编程的对比?正如 Jonas 在这个回答中所指出的那样。

-- missingfaktor

Commented Oct 16, 2010 at 9:22

The real answer is - theres's no "versus" between them. Check out this question at StackOverflow.

真正的答案是------二者之间不存在所谓的"对立关系"。可以参考 Stack Overflow 上的这个问题

-- missingfaktor

Commented Oct 18, 2010 at 3:03

Answers

回答

I would say that it is more Functional Programming vs Imperative Programming .

我认为更值得对比的是函数式编程命令式编程

The biggest difference is that Imperative programming is about Control flow while Functional programming is about Data flow . Another way to say it is that functional programming only uses expressions while in imperative programming both expressions and statements are used.

二者最显著的区别在于,命令式编程围绕控制流 展开,而函数式编程围绕数据流 展开。换一种表述方式:函数式编程仅使用表达式 ,而命令式编程同时使用表达式语句

For example, in imperative programming variables and loops are common when handling state, while in functional programming the state is handled via parameter passing, which avoids side-effects and assignments.

例如,在命令式 编程中,处理状态时通常会使用变量与循环;而在函数式编程中,状态通过参数传递的方式处理,这种方式可以避免副作用与赋值操作。

Imperative pseudo-code for a function for calculate the sum of a list (the sum is kept in a variable):

用于计算列表元素和的命令式伪代码(累加和存储在变量中):

复制代码
int sumList(List<int> list) {
int sum = 0;
for(int n = 0; n < list.size(); n++) {
sum = sum + list.get(n);
}

return sum;
}

Functional pseudo-code for the same function (the sum is passed as a parameter):

实现相同功能的函数式伪代码(累加和以参数形式传递):

复制代码
fun sumList([], sum) = sum
| sumList(v::lst, sum) = sumList(lst, v+sum)

I recommend the presentation Taming Effects with Functional Programming by Simon Peyton-Jones for a good introduction to functional concepts.

推荐大家观看 Simon Peyton-Jones 的演讲 《使用函数式编程驯服副作用》],该演讲对函数式编程的相关概念进行了很好的入门介绍。

edited Feb 19, 2014 at 15:49

Magus

answered Oct 5, 2010 at 21:19

Jonas

You should mention that the functional version is tail-recursive and thus optimized to avoid stack overflows. (Some people might see the recursion and think that functional programming is bad because of it)

你应当指出,上述函数式代码采用了尾递归的写法,因此可以通过编译器优化避免栈溢出问题。(部分人看到递归写法后,可能会据此认为函数式编程存在缺陷)

-- alternative

Commented Oct 5, 2010 at 22:36

+1 for describing the most important aspect of imperative vs. functional: control flow vs data flow. One thing I have to add is that functional paradigm and OO paradigm is not mutually exclusive; you can use OO paradigm to model how object (data) interacts, and functional paradigm to transform (manipulate) that object.

+1,你准确描述了命令式编程与函数式编程的核心区别:控制流与数据流。我补充一点,函数式范式与面向对象范式并非 互斥关系;你可以使用面向对象范式对对象(数据)的交互方式进行建模,同时使用函数式范式对这些对象进行转换(操作)。

-- Lie Ryan

Commented Oct 6, 2010 at 10:19

Interestingly, you can model data-as-control and control-as-data as well to intermix. FP can use Arrows and first order functions to pass control flow around and manipulate it like data. OOP uses various design patterns to use objects for altering control flow.

有趣的是,你还可以通过"以数据表示控制"和"以控制表示数据"的方式实现两种范式的融合。函数式编程可以借助 Arrows 与一阶函数传递控制流,并像操作数据一样操作控制流;面向对象编程则通过各种设计模式,利用对象来改变控制流的走向。

-- CodexArcanum

Commented Nov 1, 2010 at 15:05

I think it's also worth noting that the main difference isn't that you write the same program but you make your loops tail-recursive method calls. it's way larger than that

我认为还需要强调一点:二者的核心差异,绝不仅仅是将循环改写为尾递归调用那么简单,其差异的范畴要广泛得多。

-- sara

Commented May 1, 2016 at 18:33

Your functional example makes use of parameter pattern-matching. That isn't exclusive to functional programming, similarly functional programs can use monads and even imperative-like constructs without necessarily needing to formulate every iterative algorithm as a recursive algorithm.

你的函数式示例使用了参数模式匹配的特性,而该特性并非函数式编程所独有。同理,函数式程序也可以使用 monad 以及类命令式的结构,不必将所有迭代算法都转化为递归算法。

-- Dai

Commented Oct 5, 2017 at 9:38

Functional programming is based on a declarative model and has its roots from lambda calculus. It offers a lot of great concepts which can be borrowed from more imperative languages like C++ and C#.

函数式编程基于声明式模型,其理论根源是 λ 演算。它包含诸多优秀的编程概念,这些概念可以被 C++、C# 等命令式语言借鉴。

Some examples include referential transparency, lambda functions, first class functions, lazy and eager evaluation, and immutability.

这些概念包括引用透明性、λ 函数、头等函数、惰性求值与及早求值、不可变性等。

If for nothing else learning functional programming is useful for the concepts that it contains. It will change the way you do programming and think about programming. And I would guess that in the future functional programming will be just as important as object oriented programming has been.

即便不用于实际开发,学习函数式编程也能让你掌握这些有价值的概念。它会改变你的编程方式与编程思维。我预计,在未来,函数式编程将会和过去的面向对象编程一样重要。

To get started you can chose to use a pure functional language such as Haskell, or you can use a hybrid one like F#.

入门时,你可以选择 Haskell 等纯函数式语言,也可以选择 F# 等混合范式语言。

Most good universities will cover functional programming and if you go to school I'd highly suggest you take that course.

多数顶尖大学都会开设函数式编程相关课程,如果你目前在校,我强烈建议你选修这门课。

What are some of the big differences, pros and cons of functional programming vs. object-oriented programming?

函数式编程与面向对象编程之间存在哪些显著差异、优势与劣势?

Well object oriented programming is nice because it allows you to model your complex problem into hierarchies so you can simplify the problem. But it becomes very hard when you start to consider multi threaded programming while using mutable objects. In such cases you need to use heavy use of synchronization objects and it's near impossible to perfect a large application.

面向对象编程的优势在于,它可以将复杂的问题建模为层级结构,从而简化问题的复杂度。但当你在多线程编程场景中使用可变对象时,问题就会变得棘手。这种情况下,你需要大量使用同步对象,而要让一个大型应用程序在该场景下达到完美状态,几乎是不可能的。

That's where functional programming comes in. Because of things like immutability functional programming really simplifies multi threaded programs. It makes it almost trivially easy to parallelize something when you know that given input X to a function it will always output Y. Also you know that a variable (or value in functional programming) can't change mid use from another thread.

这正是函数式编程可以发挥优势的场景。得益于不可变性等特性,函数式编程能够极大地简化多线程程序的开发。当你明确一个函数对于输入 X X X 总会输出 Y Y Y 时,实现并行化就会变得轻而易举。此外,你可以确定,一个变量(或函数式编程中的"值")不会在使用过程中被其他线程修改。

edited Apr 12, 2017 at 7:31

CommunityBot

answered Oct 5, 2010 at 19:17

Brian R. Bondy

To be clear, Scheme is by no means a pure functional language.

需要明确的是,Scheme 绝非一门纯函数式语言。

-- Jonathan Sterling

Commented Oct 6, 2010 at 1:11

Your second last paragraph is completely bs. OO doesn't pose any problems in multithreading, mutability does. You seem to be confusing imperative programming with object-oriented programming. Is that the case?

你倒数第二段的表述完全错误。面向对象编程本身并不会给多线程带来问题,真正引发问题的是可变性。你似乎混淆了命令式编程与面向对象编程的概念,是这样吗?

-- missingfaktor

Commented Oct 16, 2010 at 15:02

@missingfaktor: No I am not confusing the concepts. An object typically has accessors, modifiers, data members and member functions. Yes not all objects need to have modifiers and you can implement them as immutable. But if you look at any arbitrary OO program, it will almost certainly have several objects which have modifiers and yet are still used by multi threads. I.e. in an OOP paradigm it's pretty rare to have everything immutable.

@missingfaktor:我并没有混淆这两个概念。一个对象通常包含访问器、修改器、数据成员与成员函数。诚然,并非所有对象都需要修改器,你也可以将对象实现为不可变的。但如果你观察任意一个面向对象程序,几乎都能发现其中存在多个带有修改器的对象,并且这些对象会被多线程同时使用。也就是说,在面向对象范式中,让所有对象都保持不可变是相当罕见的。

-- Brian R. Bondy

Commented Oct 16, 2010 at 22:24

You should read the answers to this question:

你应该读一读这个问题的回答:stackoverflow.com/questions/3949618/fp-and-oo-orthogonal/...

-- missingfaktor

Commented Oct 17, 2010 at 4:28

Also check Frank Shearar's answer here:

另外可以参考 Frank Shearar 在这个问题下的回答:programmers.stackexchange.com/questions/12423/...

-- missingfaktor

Commented Oct 17, 2010 at 4:57

13

(This answer is adapted from an answer to a closed question at StackOverflow.)

(本回答改编自 Stack Overflow 上一个已关闭问题的回答

One of the big differences between functional programming and object-oriented programming is that each one is better at a different kind of software evolution:

函数式编程与面向对象编程的一个显著区别在于,二者分别适用于不同类型的软件演化场景:

  • Object-oriented languages are good when you have a fixed set of operations on things , and as your code evolves, you primarily add new things. This can be accomplished by adding new classes which implement existing methods, and the existing classes are left alone.
    当需要对"事物"执行的操作集合固定不变,且代码演化的主要方向是新增"事物"时,面向对象语言会更具优势。这种演化可以通过新增实现现有方法的类来完成,而无需修改已有的类。
  • Functional languages are good when you have a fixed set of things , and as your code evolves, you primarily add new operations on existing things. This can be accomplished by adding new functions which compute with existing data types, and the existing functions are left alone.
    当"事物"的集合固定不变,且代码演化的主要方向是新增针对现有"事物"的操作时,函数式语言会更具优势。这种演化可以通过新增基于现有数据类型进行计算的函数来完成,而无需修改已有的函数。

When evolution goes the wrong way, you have problems:

当软件演化方向与语言适用场景不匹配时,就会出现问题:

  • Adding a new operation to an object-oriented program may require editing many class definitions to add a new method.
    若要在面向对象程序中新增一个操作,可能需要修改多个类的定义,为其添加对应的新方法。
  • Adding a new kind of thing to a functional program may require editing many function definitions to add a new case.
    若要在函数式程序中新增一种事物,可能需要修改多个函数的定义,为其添加对应的新分支逻辑。

This problem has been well known for many years; in 1998, Phil Wadler dubbed it the "expression problem". Although some researchers think that the expression problem can be addressed with such language features as mixins, a widely accepted solution has yet to hit the mainstream.

这个问题早已被业界熟知,1998 年,Phil Wadler 将其命名为"表达式问题"。尽管部分研究者认为可以通过 mixin 等语言特性解决表达式问题,但目前尚未出现被主流广泛接受的解决方案。

edited May 23, 2017 at 12:40

CommunityBot

answered Aug 28, 2014 at 20:43

Norman Ramsey

I love your answer, word of wisdoms here. I met it a few months ago and just spent 30 minutes specifically looking for it as I didn't bookmark it. Just the best explanation on OOP vs FP for those who understand the advantage of understanding concepts rather than techniques. The paper about the expression problem is also fantastic. Thanks a lot for sharing your insight, your answer is very underrated in my opinion.

我太喜欢你的回答了,字字珠玑。我几个月前读过这个回答,但当时没有收藏,今天特意花了 30 分钟才找到它。对于那些更注重理解概念而非技巧的人来说,这是关于面向对象编程与函数式编程对比的最佳解释。那篇关于表达式问题的论文也非常出色。非常感谢你分享的见解,在我看来,这个回答的价值被严重低估了。

-- tobiak777

Commented Jan 15, 2016 at 20:48


Why are side-effects considered evil in functional programming?

为什么副作用在函数式编程中被视为"禁忌"?

I feel that side effects are a natural phenomenon. But it is something like taboo in functional languages. What are the reasons?

我认为副作用是一种很自然的现象,但它在函数式语言中却近乎一种禁忌。这背后的原因是什么?

My question is specific to functional programming style. Not all programming languages/paradigms.

我的问题特指函数式编程范式,而非所有编程语言或编程范式。

edited Jan 28, 2016 at 18:40

Robert Harvey

asked Oct 28, 2010 at 6:05

Gulshan

A program without side effects is useless, so side effects are neither evil nor taboo. But FP encurages delimiting the code with side effects, so as large a part of the code as possible are side-effect free functions. This is encouraged because side-effect free functions and subsystems are easier to understand, easier to analyze, easier to test and easier to optimize.

一个没有任何副作用的程序是毫无用处的,因此副作用既非"邪恶",也非"禁忌"。但函数式编程鼓励对带有副作用的代码进行隔离,从而让程序中尽可能大的部分由无副作用函数与子系统构成。这种做法之所以被推崇,是因为无副作用的函数与子系统更易于理解、分析、测试和优化。

-- JacquesB

Commented Jan 28, 2016 at 19:34

@JacquesB It would make a good answer to explain why they are easier to understand, easier to analyse, easier to test and easier to optimize.

@JacquesB 如果你能进一步解释为什么无副作用的代码更易于理解、分析、测试和优化,会是一个很棒的回答。

-- ceving

Commented Dec 13, 2016 at 16:58

Answers

Writing your functions/methods without side effects - so they're pure functions - makes it easier to reason about the correctness of your program.

编写无副作用的函数/方法------即纯函数------能够让你更轻松地推导程序的正确性。

It also makes it easy to compose those functions to create new behaviour.

同时,纯函数可以很方便地组合在一起,实现新的功能。

It also makes certain optimisations possible, where the compiler can for instance memoise the results of functions, or use Common Subexpression Elimination.

此外,纯函数还能支持特定的编译器优化,例如函数结果的记忆化存储、公共子表达式消除等。

Edit: at Benjol's request: Because a lot of your state's stored in the stack (data flow, not control flow, as Jonas has called it here), you can parallelise or otherwise reorder the execution of those parts of your computation that are independent of each other. You can easily find those independent parts because one part doesn't provide inputs to the other.

编辑补充(应 Benjol 的要求):由于程序的大部分状态都存储在栈中(正如 Jonas 在这个回答中所提及的,这是数据流而非控制流的特点),你可以对计算过程中相互独立的部分进行并行化或重排序执行。这些独立部分很容易识别,因为它们之间不存在输入输出的依赖关系。

In environments with debuggers that let you roll back the stack and resume computing (like Smalltalk), having pure functions means that you can very easily see how a value changes, because the previous states are available for inspection. In a mutation-heavy calculation, unless you explicitly add do/undo actions to your structure or algorithm, you cannot see the history of the computation. (This ties back to the first paragraph: writing pure functions makes it easier to inspect the correctness of your program.)

在支持栈回滚与计算恢复的调试环境中(例如 Smalltalk),使用纯函数意味着你可以轻松地追踪一个值的变化过程,因为所有历史状态都可以被查看。而在一个大量使用可变状态的计算过程中,除非你在数据结构或算法中显式添加执行/撤销操作,否则无法查看计算的历史过程。(这一点与第一段内容呼应:编写纯函数能够让你更轻松地验证程序的正确性。)

edited Apr 12, 2017 at 7:31

CommunityBot

answered Oct 28, 2010 at 6:33

Frank Shearar

Maybe consider adding something about concurrency in your answer?

或许你可以在回答中补充一些关于并发的内容?

-- Benjol

Commented Oct 28, 2010 at 8:48

Side-effect free functions are easier to test and to reuse.

无副作用的函数更易于测试和复用。

-- LennyProgrammers

Commented Oct 28, 2010 at 10:56

@Lenny222: reuse was what I was hinting at by talking about function composition.

@Lenny222:我在提到函数组合时,其实已经隐含了"复用"这一点。

-- Frank Shearar

Commented Oct 28, 2010 at 11:22

@Frank: Ah, ok, too shallow browsing. :

@Frank:啊,抱歉,我刚才看得不够仔细。:)

-- LennyProgrammers

Commented Oct 28, 2010 at 11:38

@Lenny222: It's ok; it's probably a good thing to spell it out.

@Lenny222:没关系,把这一点明确说出来或许更好。

-- Frank Shearar

Commented Oct 28, 2010 at 11:56

31

From an article about Functional programming:

引自一篇关于函数式编程的文章:

In practice, applications need to have some side effects. Simon Peyton-Jones, a major contributor to the functional programming language Haskell, said the following: "In the end, any program must manipulate state. A program that has no side effects whatsoever is a kind of black box. All you can tell is that the box gets hotter." (http://oscon.blip.tv/file/324976) The key is to limit side effects, clearly identify them, and avoid scattering them throughout the code.

在实际开发中,应用程序不可避免地会产生一些副作用。函数式编程语言 Haskell 的主要设计者之一 Simon Peyton-Jones 曾说过:"归根结底,任何程序都必须操作状态。一个完全没有副作用的程序就像一个黑箱,你唯一能观察到的变化,就是这个箱子变得更热了。"(http://oscon.blip.tv/file/324976)问题的关键在于限制副作用的范围、清晰地标记副作用,并且避免让副作用分散在代码的各个角落。

answered Oct 28, 2010 at 10:08

Peter Stuifzand

oscon.blip.tv/file/324976 has been replaced by youtube.com/watch?v=iSmkqocn0oQ&t=3m20s.

-- Gaurav

Commented Feb 11, 2015 at 9:11

30

You've got it wrong, functional programming promotes limiting side effects to make programs easy to understand and optimize. Even Haskell allows you to write to files.

你的理解存在偏差,函数式编程倡导的是限制副作用的使用,从而让程序更易于理解和优化。即便是 Haskell 这样的纯函数式语言,也支持文件写入等带有副作用的操作。

Essentially what I am saying is that functional programmers don't think side effects are evil, they simply think limiting the use of side effects is good. I know it may seem like such a simple distinction but it makes all the difference.

本质上,我想表达的是:函数式程序员并不认为副作用是"邪恶"的,他们只是认为限制副作用的使用是一种良好的实践。我知道这看起来只是一个细微的区别,但这个区别却至关重要。

edited Oct 28, 2010 at 14:41

answered Oct 28, 2010 at 6:26

ChaosPandion

Which is why they're "something like taboo" - FPLs encourage you to limit side effects.

这正是副作用在函数式语言中近乎"禁忌"的原因------函数式编程语言鼓励你限制副作用的使用。

-- Frank Shearar

Commented Oct 28, 2010 at 6:30

+1 for the approach. side effects still exist. indeed, they are limited

+1,这个解释很到位。副作用依然存在,只是其使用范围被限制了。

-- Belun

Commented Oct 28, 2010 at 9:22

For clarification, I haven't said 'why side effect is not allowed in functional programming' or 'why side effect is not needed'. I know It IS allowed in functional languages and sometimes is a must. But it is very much discouraged in functional programming. Why? That was my question.

为了澄清一点:我并没有问"为什么函数式编程不允许副作用"或者"为什么函数式编程不需要副作用"。我知道函数式语言中是允许副作用的,而且在某些场景下副作用是必需的。但函数式编程确实强烈不鼓励使用副作用,这才是我想问的原因。

-- Gulshan

Commented Oct 28, 2010 at 9:25

@Gulshan - Because side effects make programs harder to understand and optimize.

@Gulshan ------ 因为副作用会让程序变得更难理解和优化。

-- ChaosPandion

Commented Oct 28, 2010 at 14:00

in the case of haskell, the main point isn't to "limit side effects". side effects are impossible to express in the LANGUAGE. what functions like readFile are doing is defining a sequence of actions. this sequence is functionally pure and is kind of like an abstract tree describing WHAT to do. the actual dirty side effects are then carried out by the runtime.

以 Haskell 为例,其核心思路并非"限制副作用"。在该语言的语法层面,副作用本身是无法直接表达的。诸如 readFile 这样的函数,其作用是定义一个操作序列。这个序列是函数式纯的,它就像一棵抽象语法树,用于描述"需要执行什么操作"。而真正带有副作用的具体执行过程,则是由运行时系统来完成的。

-- sara

Commented Jun 30, 2016 at 13:45

I primarily work in functional code now, and from that perspective it seems blindingly obvious. Side effects create a huge mental burden on programmers trying to read and understand code. You don't notice that burden until you are free from it for a while, then suddenly have to read code with side effects again.

我目前的工作主要围绕函数式代码展开,从这个角度来看,答案显而易见。副作用会给阅读和理解代码的程序员带来巨大的心智负担。这种负担在你习惯无副作用的代码之前很难被察觉,而当你习惯之后,再回头阅读带有副作用的代码时,这种负担就会凸显出来。

Consider this simple example:

请看下面这个简单的例子:

scala 复制代码
val foo = 42
// Several lines of code you don't really care about, but that contain a
// lot of function calls that use foo and may or may not change its value
// by side effect.

// Code you are troubleshooting
// What's the expected value of foo here?

In a functional language, I know that foo is still 42. I don't even have to look at the code in between, much less understand it, or look at the implementations of the functions it calls.

在函数式语言中,我可以确定 foo 的值仍然是 42。我甚至不需要查看中间的代码,更不必去理解这些代码,或者查看其中调用函数的具体实现。

All that stuff about concurrency and parallelization and optimization is nice, but that's what computer scientists put on the brochure. Not having to wonder who's mutating your variable and when is what I really enjoy in day to day practice.

并发、并行化和优化这些特性固然很好,但这些更像是计算机科学家们用来宣传的亮点。在日常开发中,真正让我受益的是:我不必再去猜测哪个地方、哪个时间点修改了我的变量。

answered Jan 28, 2016 at 17:44

Karl Bielefeldt

Some languages have const specifiers for function parameters, so that you know if a function can modify values or not.

一些编程语言为函数参数提供了 const 限定符,通过这个限定符,你可以判断一个函数是否会修改参数的值。

-- Nuclear

Commented Feb 19, 2021 at 8:47

A few notes:

补充几点:

  • Functions without side effects can trivialy be executed in parallel, while functions with side effects typically require some sort of synchronisation.
    无副作用的函数可以很容易地实现并行执行,而带有副作用的函数通常需要某种形式的同步机制。
  • Functions without side effects allow for a more aggressive optimization (e.g. by transparentely using an result cache), because as long as we get the right result, it doesn't even matter whether or not the function was really executed
    无副作用的函数支持更激进的优化(例如透明地使用结果缓存),因为只要能得到正确的结果,函数是否被实际执行过并不重要。

edited Dec 23, 2010 at 0:15

answered Oct 28, 2010 at 9:19

user281377

Very interesting point: it doesn't even matter whether or not the function was really executed . It would be interesting to end up with a compiler that can get rid of subsequent calls to side effect free functions given equivalent parameters.

这个观点非常有意思:函数是否被实际执行过并不重要 。如果能设计出这样一种编译器------当传入的参数相同时,编译器可以自动省略对无副作用函数的重复调用------那将会非常有趣

-- Noël Widmer

Commented Oct 25, 2017 at 12:29

@NoelWidmer Something like that already exists. Oracle's PL/SQL offers a deterministic clause for functions without side effects, so they do not get executed more often than necessary.

@NoelWidmer 类似的特性其实已经存在了。Oracle 的 PL/SQL 为无副作用函数提供了 deterministic 子句,通过该子句可以避免函数被不必要地重复执行。

-- user281377

Commented Oct 25, 2017 at 13:54

Wow! However, I think languages should be semantically expressive so that the compiler can figure it out by itself without having to specify an explicit flag (I am unsure what a clause is). A solution could be to specify parameters to be mutable/immutable f.e. Generally speaking, this would require a strong type system in which assumptions about side effects can be made by the compiler. And the feature would need to be able to be turned off if desired. Opt-out instead of opt-in. That's just my opinion, based on the limited knowledge I have since I read your answer :

哇!不过,我认为编程语言应该具备足够的语义表达能力,这样编译器就能自动识别无副作用函数,而无需程序员显式添加标记(我不太清楚"子句"具体指什么)。一种可行的方案是,允许程序员指定参数的可变性/不可变性。一般来说,这需要一个强大的类型系统作为支撑,编译器才能基于该系统对函数的副作用做出推断。此外,如果有需要,这个特性 应该可以被关闭------采用"默认开启、按需关闭"的模式,而非"默认关闭、按需开启"。这只是我的个人看法,基于我阅读完你的回答后所形成的有限认知 :)

-- Noël Widmer

Commented Oct 25, 2017 at 13:59

The deterministic clause is just a keyword that tells the compiler that this is a deterministic function, comparable to how the final keyword in Java tells the compiler that the variable cannot change.
deterministic 子句本质上是一个关键字,它用于告知编译器当前函数是一个确定性函数。这与 Java 中的 final 关键字的作用类似------final 关键字用于告知编译器对应的变量是不可变的。

-- user281377

Commented Oct 26, 2017 at 15:59


Are FP and OO orthogonal?

函数式编程与面向对象编程是否正交?

I have heard this time and again, and I am trying to understand and validate the idea that FP and OO are orthogonal.

我曾多次听闻这个观点,现在我正尝试理解并验证"函数式编程与面向对象编程二者正交"这一说法。

First of all, what does it mean for 2 concepts to be orthogonal?

首先,两个概念正交意味着什么?

FP encourages immutability and purity as much as possible, while OO seems built for state and mutation -- a slightly organized version of imperative programming? I realize that objects can be immutable, but OO seems to imply state/change to me.

函数式编程尽可能倡导不可变性与纯函数特性,而面向对象编程似乎是为状态与可变操作而生------它是否可以被看作是一种结构更规整的命令式编程?我固然知道对象也可以被设计为不可变的,但在我看来,面向对象编程本身就隐含了状态与变化的属性。

They seem like opposites. How does that affect their orthogonality?

它们看起来像是对立的概念,这一点又会如何影响二者的正交性呢?

A language like Scala makes it easy to do OO and FP both, does this affect the orthogonality of the two methods?

像 Scala 这样的语言可以同时轻松支持面向对象编程与函数式编程,这是否会对这两种编程范式的正交性产生影响?

edited Oct 21, 2010 at 13:36

Jonas

asked Oct 16, 2010 at 15:59ct 16, 2010 at 15:59

letronje

Answers

个回答

Orthogonality implies that two things are unrelated. It comes from mathematics where it means perpendicular. In common usage it can mean two decisions are unrelated or that one subject is irrelevant when considering another subject. As used here, orthogonal means that one concept doesn't either imply or exclude the other.

正交性 指的是两个事物之间互不关联。该概念源自数学领域,在数学中它表示垂直。在日常语境中,它可以指两个决策相互独立,或者在考量某一对象时,另一对象的存在不构成影响。在本文的语境下,正交性指的是一个概念既不会推导得出另一个概念,也不会排斥另一个概念。

The two concepts object oriented programming and functional programming are not incompatible with each other. Object orientedness does not imply mutability. Many people who are introduced to object oriented programs the traditional way often first use C++, Java, C# or similar languages where mutability is common and even encouraged (standard libraries provide a variety of mutable classes for people to use). Therefore it is understandable that many people associate object oriented programming with imperative programming and mutability, as this is how they have learned it.

面向对象编程 与 函数式编程 这两个概念并非互斥。面向对象这一属性并不意味着可变性。许多通过传统途径接触面向对象编程的人,最初使用的往往是 C++、Java、C# 这类语言,在这些语言中,可变性是一种常见特性,甚至是被鼓励的(标准库会提供多种可变类供开发者使用)。因此,许多人会将面向对象编程与命令式编程、可变性联系在一起,这是基于他们的学习经历形成的认知,是可以理解的。

However object oriented programming covers topics like:

但面向对象编程的核心范畴包括以下几点:

  • Encapsulation

    封装

  • Polymorphism

    多态

  • Abstraction

    抽象

None of this implies mutability, and none of it excludes functional programming. So yes they are orthogonal in that they are different concepts. They are not opposites - you can use one, or the other, or both (or even neither). Languages like Scala and F# attempt to combine both paradigms into a single language:

以上几点均不隐含可变性的要求,同时也不排斥函数式编程。因此,从二者属于不同概念这一角度来说,它们确实是正交的。二者并非对立关系------你可以选择其中一种范式,也可以两种同时使用,甚至可以两种都不使用。Scala 与 F# 这类语言就尝试将两种范式整合在同一门语言中:

Scala is a multi-paradigm programming language designed to integrate features of object-oriented programming and functional programming .

Scala 是一门多范式编程语言,其设计目标是整合面向对象编程与函数式编程的特性

Source

F# is a succinct, expressive and efficient functional and object-oriented language for .NET which helps you write simple code to solve complex problems.

F# 是一门简洁、高效且表现力丰富的 .NET 平台函数式面向对象编程语言,它可以帮助开发者用简洁的代码解决复杂的问题。

edited Oct 21, 2010 at 13:29

answered Oct 16, 2010 at 16:07

Mark Byers

Comments

Pascal Cuoq

I was going to question the formulation "OO is about ...", because I didn't think that defined OO (functional programming is very much about polymorphism and abstraction too). But before I had time to, you edited it to something I can't quibble.

我原本想对你"面向对象编程是关于......"的表述提出质疑,因为我认为这个表述不足以定义面向对象编程(函数式编程同样也高度强调多态与抽象)。但我还没来得及提出质疑,你就已经对内容进行了修改,修改后的表述让我无从反驳。

Landei

Scala inventor Martin Odersky calls Scala a "post-functional" language, which stands for a pragmatic approach that combines the most useful existing features regardless where they come from. Following this schema, one could call Java a dys-functional language, which is true but slightly off-topic...

Scala 语言的设计者 Martin Odersky 将 Scala 称为"后函数式"语言,这一称谓代表了一种务实的设计理念------整合现有各类范式中最实用的特性,而不局限于特性的来源。按照这个逻辑,有人或许会把 Java 称为"非函数式"语言,这种说法虽然没错,但有点偏离主题了......

Debilski

But obviously, the inventors and the distributors use these terms for marketing reasons. These quotes should be subject to discussion and not used as a supporting argument.

但显然,这些语言的设计者和推广者使用这些称谓是出于营销目的。这些引文本身是值得商榷的,不应被当作支撑论点的依据。

soc

I don't agree that object-oriented and functional are "completely unrelated concepts", language designers who have a good understanding of both are able to integrate these two concepts into each other. This answer might be interesting, if you want to compare the approach different languages designers took:

我并不认同"面向对象编程与函数式编程是完全不相关的概念"这一说法。对两种范式都有深入理解的语言设计者,完全可以将二者有机地融合在一起。如果你想对比不同语言设计者采用的融合方案,这个回答或许会对你有帮助:stackoverflow.com/questions/3644251/...

jbmilgrom

It might be true that object-oriented programming has become associated with abstraction, encapsulation, etc, notwithstanding mutability. However, it seems to be a bit of a stretch to talk about the semantics of "objects" without mention of an identity that can withstand change i.e. mutability. see softwarefordays.com/post/..., and chapter 3 in mitpress.mit.edu/sites/default/files/sicp/full-text/book/...

尽管面向对象编程与可变性脱不开关联,但它确实已经与抽象、封装等概念紧密绑定。不过,如果在讨论"对象"的语义时,完全不提及对象具备的、能够在变化中保持一致的标识------也就是可变性,似乎有些牵强。

First of all, what does it mean for 2 concepts to be orthogonal ?

首先,两个概念正交意味着什么?

It means that the two concepts do not have contrasting ideas or are not incompatible with each other.

这意味着两个概念之间不存在对立的内涵,也并非互斥关系。

FP encourages immutability and purity as much as possible. and OO seems like something that is built for state and mutation(a slightly organized version of imperative programming?). And I do realize that objects can be immutable. But OO seems to imply state/change to me.

函数式编程尽可能倡导不可变性与纯函数特性,而面向对象编程似乎是为状态与可变操作而生------它是否可以被看作是一种结构更规整的命令式编程?我固然知道对象也可以被设计为不可变的,但在我看来,面向对象编程本身就隐含了状态与变化的属性。

They seem like opposites. How does it affect their orthogonality ?

它们看起来像是对立的概念,这一点又会如何影响二者的正交性呢?

A language like Scala makes it easy to do OO and FP both, does this affect the orthogonality of the 2 methods ?

像 Scala 这样的语言可以同时轻松支持面向对象编程与函数式编程,这是否会对这两种编程范式的正交性产生影响?

OO is about encapsulation, object composition, data abstraction, polymorphism via subtyping, and controlled mutation when necessary (immutability is encouraged in OO as well). FP is about function composition, control abstraction, and constrained polymorphism (aka parametric polymorphism). Thus the two ideas are not contradictory. They both provide you with different kinds of powers and abstraction mechanisms, which are certainly possible to have in one language. In fact, this is the thesis on which Scala was built!

面向对象编程的核心是封装、对象组合、数据抽象、基于子类型的多态,以及在必要时进行可控的可变操作(不可变性在面向对象编程中同样是被鼓励的)。函数式编程的核心是函数组合、控制抽象,以及受限多态(也称为参数多态)。因此,这两种理念并不矛盾。它们各自提供了不同的能力与抽象机制,而这些能力与机制完全可以共存于同一门编程语言中。事实上,Scala 语言的设计初衷正是基于这一论点!

In his Scala Experiment talk at Google, Martin Odersky explains it very well how he believes the two concepts - OO and FP - are orthogonal to each other and how Scala unifies the two paradigms elegantly and seamlessly into a new paradigm popularly known in Scala community as object-functional paradigm. Must watch talk for you.

在谷歌举办的 Scala 实验主题演讲中,Martin Odersky 详细阐述了他对面向对象编程与函数式编程二者正交的理解,同时也讲解了 Scala 是如何将这两种范式优雅且无缝地整合为一种新范式的------这种新范式在 Scala 社区中被称为"对象-函数式范式"。这个演讲非常值得你一看。

Other examples of object-functional languages: OCaml, F#, Nemerle.

其他支持对象-函数式范式的语言示例:OCaml、F#、Nemerle。

edited Jun 20, 2020 at 9:12

answered Oct 16, 2010 at 16:30

missingfaktor

Comments

letronje

Here is the Youtube link for easy download

这里提供一个便于下载的 YouTube 链接 ~> youtube.com/watch?v=01rXrI6xelE

jneira

My point is although oop and fp are not opposite in general there is some points in which you have to choose a functional or a oop aprox. One of the characteristics of oop is to bind data and behaviour and in fp, although you can do it, it is not the standar. Another char. is the organization of data and the type system in a hierarchical fashion (with inheritance in most cases) to rule the abstractions and polymorphism. Maybe with fp that scene is possible but it is not popular.

我的观点是,尽管面向对象编程与函数式编程总体上并非对立关系,但在某些场景下,你必须在两种范式中选择其一。面向对象编程的特性之一是将数据与行为绑定在一起,而在函数式编程中,虽然也能实现这一点,但这并非标准做法。面向对象编程的另一特性是,以层级化的方式组织数据与类型系统(大多数情况下会使用继承),以此实现抽象与多态。函数式编程或许也能实现这种场景,但这种做法并不常见。

Deduplicator

orthogonality doesn't only mean not conflicting. It also means one does not imply the other.

正交性的含义不仅是不冲突,还包括一个概念不能推导得出另一个概念。

First of all, what does it mean for 2 concepts to be orthogonal?

首先,两个概念正交意味着什么?

It means they don't affect each other. I.e. a functional language isn't less functional because it's also object oriented.

这意味着两个概念互不影响。也就是说,一门函数式语言不会因为同时支持面向对象编程,就降低其函数式特性的纯度。

They seem like opposites. How does it affect their orthogonality?

它们看起来像是对立的概念,这一点又会如何影响二者的正交性呢?

If they were opposites (i.e. a purely functional language could not possibly be object oriented), they would by definition not be orthogonal. However I do not believe that this is the case.

如果二者是对立关系(例如,一门纯函数式语言完全不可能同时支持面向对象编程),那么根据定义,它们就不是正交的。但我认为事实并非如此。

and OO seems like something that is built for state and mutation(a slightly organized version of imperative programming?). And I do realize that objects can be immutable. But OO seems to imply state/change to me.

而面向对象编程似乎是为状态与可变操作而生------它是否可以被看作是一种结构更规整的命令式编程?我固然知道对象也可以被设计为不可变的,但在我看来,面向对象编程本身就隐含了状态与变化的属性。

While this is true for most mainstream OO languages, there is no reason that an OO language needs to have mutable state.

虽然大多数主流面向对象语言确实如此,但从理论上来说,一门面向对象语言并不一定需要支持可变状态。

If a language has objects, methods, virtual inheritance and ad-hoc polymorphism, it's an object oriented language - whether it also has mutable state or not.

只要一门语言具备对象、方法、虚继承与特设多态这些特性,它就是一门面向对象语言------无论它是否同时支持可变状态。

edited Oct 17, 2010 at 10:51

answered Oct 16, 2010 at 16:09

sepp2k


[Functional programming vs Object Oriented programming closed]

函数式编程与面向对象编程对比

I've been mainly exposed to OO programming so far and am looking forward to learning a functional language. My questions are:

到目前为止,我的编程经验主要集中在面向对象编程领域,现在我希望学习一门函数式编程语言。我的问题如下:

  • When do you choose functional programming over object-oriented?

    在什么场景下,应该优先选择函数式编程而非面向对象编程?

  • What are the typical problem definitions where functional programming is a better choice?

    哪些典型的问题场景更适合使用函数式编程来解决?

edited Aug 22, 2017 at 12:23

Olivier Lalonde

Duplicate: stackoverflow.com/questions/552336/...

重复问题:stackoverflow.com/questions/552336/...

-- gnovice

Commented Jan 16, 2010 at 22:23

this is relevant

相关问题参考 programmers.stackexchange.com/questions/9730/...

-- kirill_igum

Commented Sep 11, 2013 at 2:14

-- kirill_igum

similar question cs.se also closed what is example where functional programming gives better results than imperative style. conventional wisdom seems to be that one is not superior to the other, or they are not comparable on simple criteria, or that they are used for different purposes... functional programming has more scientific/academic origins & uses and is less common in industry, so the question also sets up an "industry vs academia" unresolvable pov/conflict. one classic ref that shows OOP sytle in functional programming, SICP book/MIT

计算机科学领域也有一个类似的已关闭问题:有哪些函数式编程比命令式编程效果更好的例子。业界的普遍观点是,两种范式之间不存在优劣之分,无法用简单的标准进行比较,它们的适用场景本就不同......函数式编程起源于学术与科研领域,在工业界的应用相对较少,因此这个问题也隐含了"工业界 vs 学术界"这种难以调和的立场冲突。有一本经典著作展示了如何在函数式编程中体现面向对象风格,即麻省理工学院的《计算机程序的构造和解释》(SICP)。

-- vzn

Commented Apr 27, 2014 at 15:19

"OO makes code understandable by encapsulating moving parts. FP makes code understandable by minimizing moving parts. " --Micheal Feathers, 2010

"面向对象编程通过封装可变部分,让代码变得易于理解。函数式编程通过最小化可变部分,让代码变得易于理解。 "------迈克尔·费瑟斯,2010 年

-- jaco0646

Commented Mar 17, 2020 at 0:19

-- jaco0646

4Answers

When do you choose functional programming over object oriented?

在什么场景下,应该优先选择函数式编程而非面向对象编程?

When you anticipate a different kind of software evolution:

当你预期软件会朝着特定方向演化时,应优先选择函数式编程:

  • Object-oriented languages are good when you have a fixed set of operations on things , and as your code evolves, you primarily add new things. This can be accomplished by adding new classes which implement existing methods, and the existing classes are left alone.

    当需要对"事物"执行的操作集合固定不变,且代码演化的主要方向是新增"事物"时,面向对象语言会更具优势。这种演化可以通过新增实现现有方法的类来完成,而无需修改已有的类。

  • Functional languages are good when you have a fixed set of things , and as your code evolves, you primarily add new operations on existing things. This can be accomplished by adding new functions which compute with existing data types, and the existing functions are left alone.

    当"事物"的集合固定不变,且代码演化的主要方向是新增针对现有"事物"的操作时,函数式语言会更具优势。这种演化可以通过新增基于现有数据类型进行计算的函数来完成,而无需修改已有的函数。

When evolution goes the wrong way, you have problems:

当软件演化方向与语言适用场景不匹配时,就会出现问题:

  • Adding a new operation to an object-oriented program may require editing many class definitions to add a new method.

    若要在面向对象程序中新增一个操作,可能需要修改多个类的定义,为其添加对应的新方法。

  • Adding a new kind of thing to a functional program may require editing many function definitions to add a new case.

    若要在函数式程序中新增一种事物,可能需要修改多个函数的定义,为其添加对应的新分支逻辑。

This problem has been well known for many years; in 1998, Phil Wadler dubbed it the "expression problem". Although some researchers think that the expression problem can be addressed with such language features as mixins, a widely accepted solution has yet to hit the mainstream.

这个问题早已被业界熟知,1998 年,菲尔·瓦德勒将其命名为"表达式问题"。尽管部分研究者认为可以通过 mixin 等语言特性解决表达式问题,但目前尚未出现被主流广泛接受的解决方案。

What are the typical problem definitions where functional programming is a better choice?

哪些典型的问题场景更适合使用函数式编程来解决?

Functional languages excel at manipulating symbolic data in tree form. A favorite example is compilers, where source and intermediate languages change seldom (mostly the same things ), but compiler writers are always adding new translations and code improvements or optimizations (new operations on things). Compilation and translation more generally are "killer apps" for functional languages.

函数式语言在处理树形结构的符号数据方面表现出色。编译器就是一个典型的例子:在编译器的开发过程中,源语言与中间语言的结构很少发生变化(即"事物"基本保持不变),但编译器开发者需要不断新增代码翻译、优化等功能(即针对现有"事物"新增操作)。编译器以及更广义的翻译类程序,是函数式语言的"杀手级应用场景"。

edited Jan 28, 2025 at 13:52

Norman Ramsey

Comments

Jacobs Data Solutions

雅各布斯数据解决方案

There is some serious zen behind this answer. I think it illuminates the fact that certain OOP design patterns (Visitor) are actually hacks which attempt to overcome the problem of adding new operations.

这个回答蕴含着深刻的哲理。它揭示了一个事实:某些面向对象设计模式(例如访问者模式),本质上是为了克服"新增操作"这一难题而采用的变通方案。

Erik Reppen

In JavaScript, you can have all of the things.

在 JavaScript 中,你可以同时使用所有编程范式的特性。

Norman Ramsey

@ErikReppen at which point the question arises, when do you choose to use the functional features, and when do you choose to use the object-oriented features?

@ErikReppen 那么问题就来了,你在什么场景下会选择使用函数式特性,又在什么场景下会选择使用面向对象特性呢?

Erik Reppen

@NormanRamsey It's not at all uncommon to mix it up in JS and first-class functions are tied to a lot of JS OOP-related features. JS's array sorting takes functions as an arg which can produce some powerful data structures. Closures + a passed function is used to keep jquery objects very lightweight memory-speaking since most methods are just references. Etc...

@NormanRamsey 在 JavaScript 中混合使用多种范式是非常常见的做法,而且头等函数与 JavaScript 中许多面向对象相关的特性密切相关。例如,JavaScript 的数组排序方法可以接收函数作为参数,借助这一特性可以构建出功能强大的数据结构;闭包与传入的函数结合使用,能够让 jQuery 对象的内存占用保持在较低水平,因为大部分方法都只是简单的引用。诸如此类的例子还有很多......

Giorgio

@NormanRamsey: Very good answer, along the lines of SICP. According to this classification, functional and procedural programming are grouped together on the opposite side of object-oriented programming. This could explain the boom of OOP during the late 1980-ies early 1990-ies: when GUIs became mainstream OOP proved to be a good approach for modeling them because you normally have a fixed set of operations (paint, open, close, resize) and a growing number of widgets. Of course, this does not mean that OOP is better than procedural for any application, as you illustrated.

@NormanRamsey:这个回答非常精彩,与《计算机程序的构造和解释》(SICP)的观点一脉相承。根据这个分类方式,函数式编程与命令式编程被归为一类,与面向对象编程相对立。这一点可以解释 20 世纪 80 年代末至 90 年代初面向对象编程的兴起:当时图形用户界面(GUI)成为主流,面向对象编程被证明是构建图形用户界面的理想范式,因为在图形用户界面中,操作集合通常是固定的(例如绘制、打开、关闭、调整大小),而控件的种类却在不断增加。当然,正如你所阐述的,这并不意味着面向对象编程在所有应用场景下都优于命令式编程。

You don't necessarily have to choose between the two paradigms. You can write software with an OO architecture using many functional concepts. FP and OOP are orthogonal in nature .

你不一定必须在两种范式之间做出选择。你可以采用面向对象的架构来编写软件,同时融入大量函数式编程的理念。函数式编程与面向对象编程本质上是正交的

Take for example C#. You could say it's mostly OOP, but there are many FP concepts and constructs. If you consider Linq , the most important constructs that permit Linq to exist are functional in nature: lambda expressions .

以 C# 语言为例。你可以认为它主要是一门面向对象语言,但它同时也包含了许多函数式编程的概念与语法结构。就拿 Linq 来说,支撑 Linq 实现的核心语法结构就带有函数式编程的特质:λ 表达式

Another example, F#. You could say it's mostly FP, but there are many OOP concepts and constructs available. You can define classes, abstract classes, interfaces, deal with inheritance. You can even use mutability when it makes your code clearer or when it dramatically increases performance.

再举一个例子,F# 语言。你可以认为它主要是一门函数式语言,但它同样提供了许多面向对象编程的概念与语法结构。你可以在 F# 中定义类、抽象类、接口,也可以实现继承。甚至在某些场景下,当可变操作能够让代码更简洁,或者能够显著提升性能时,你也可以使用可变操作。

Many modern languages are multi-paradigm.

许多现代编程语言都是多范式语言。

推荐阅读

As I'm in the same boat (OOP background, learning FP), I'd suggest you some readings I've really appreciated:

我和你有着相似的背景(从面向对象编程转向学习函数式编程),因此我想向你推荐一些我个人非常喜欢的读物:

  • Functional Programming for Everyday .NET Development , by Jeremy Miller. A great article (although poorly formatted) showing many techniques and practical, real-world examples of FP on C#.
    《面向日常 .NET 开发的函数式编程》,作者杰里米·米勒。这是一篇非常优秀的文章(尽管排版有些简陋),文中展示了多种函数式编程技巧,以及在 C# 中应用函数式编程的真实案例。

  • Real-World Functional Programming , by Tomas Petricek. A great book that deals mainly with FP concepts, trying to explain what they are, when they should be used. There are many examples in both F# and C#. Also, Petricek's blog is a great source of information.
    《函数式编程实战》,作者托马斯·佩特里切克。这是一本非常棒的著作,主要讲解函数式编程的各类概念,阐释了这些概念的内涵与适用场景。书中包含大量 F# 与 C# 的示例代码。

edited Jun 20, 2020 at 9:12

Bruno Reis

Comments

Paolo

Not forgetting you can mix F# and C# code together so you can leverage the best of each

别忘了,你还可以将 F# 代码与 C# 代码混合使用,从而充分发挥两种语言各自的优势。

Dykam

Your answer is a great example of the power of .Net. It shows it is able to leverage the powers of both paradigms.

你的回答充分展示了 .NET 平台的强大之处,它能够同时发挥两种编程范式的优势。

Dykam

Heh, sorry if I started some flaming. I didn't mean to say other platforms are less powerfull, just that .NET doesn't only support OOP. For example it has tail call optimization.

哈哈,如果我的发言引发了争论,我深表歉意。我并不是说其他平台不够强大,只是想强调 .NET 平台并非只支持面向对象编程。例如,它还支持尾调用优化。

nawfal

I dont think FP and OOP are orthogonal. Using functional constructs is not the same as functional programming. Sure using functional constructs like lambdas in Linq makes it less OO, but it still isn't functional programming. FP is where functions are first class citizens where as OOP is when classes are first class building blocks (or something to that effect - I do realise there are many kinds of OOP). Imo, the right phrasing is "there are multi-paradigm languages which lets you write both OOP constructs as well as FP constructs making both less OOP and less FP in the process".

我并不认为函数式编程与面向对象编程是正交的。使用函数式编程的语法结构,并不等同于使用函数式编程范式。诚然,在 Linq 中使用 λ 表达式这类函数式结构,会让代码的面向对象特性有所减弱,但这并不等同于函数式编程。函数式编程的核心是将函数作为头等公民,而面向对象编程的核心是将类作为首要的构建单元(大致是这个意思------我也知道面向对象编程本身也分为多种类型)。在我看来,更准确的表述应该是:"存在一类多范式语言,它们允许你同时编写面向对象与函数式的代码结构,但这样做的代价是,代码的面向对象特性与函数式特性都会有所弱化。"

user201891

@nawfal, until you can point at some intrinsic features in the two paradigms and say that they're incompatible, they're orthogonal: that is the heart of the discussion. FP is incompatible with imperative programming by definition, but OOP is not limited to imperative programming. The reason we have different words for these concepts is so that we can talk about them: when you lump them together, you just force us to needlessly come up with new words.

@nawfal,除非你能指出两种范式中存在本质上互斥的特性,否则它们就是正交的------这正是本次讨论的核心。根据定义,函数式编程与命令式编程是互斥的,但面向对象编程并不局限于命令式编程的范畴。我们之所以为这些概念赋予不同的名称,就是为了能够清晰地对它们进行讨论:如果你将它们混为一谈,只会迫使我们不得不创造一些新的词汇来指代这些概念,这完全是多此一举。

Object Oriented Programming offers:

面向对象编程提供了以下特性:

  1. Encapsulation, to

    封装,其作用是

    • control mutation of internal state
      控制内部状态的可变操作
    • limit coupling to internal representation
      降低代码与内部数据结构的耦合度
  2. Subtyping, allowing:

    子类型化,其作用是

    • substitution of compatible types (polymorphism)
      实现兼容类型的替换(多态性)
    • a crude means of sharing implementation between classes (implementation inheritance)
      为类之间共享实现逻辑提供一种直接的方式(实现继承)

Functional Programming, in Haskell or even in Scala, can allow substitution through more general mechanism of type classes. Mutable internal state is either discouraged or forbidden. Encapsulation of internal representation can also be achieved. See Haskell vs OOP for a good comparison.

在 Haskell 甚至 Scala 这类函数式语言中,可以通过类型类这种更通用的机制实现类型替换。可变的内部状态在这类语言中要么不被鼓励,要么被完全禁止。内部数据结构的封装同样也可以实现。关于这一点的详细对比,可以参考 Haskell 与面向对象编程。

Norman's assertion that "Adding a new kind of thing to a functional program may require editing many function definitions to add a new case." depends on how well the functional code has employed type classes. If Pattern Matching on a particular Abstract Data Type is spread throughout a codebase, you will indeed suffer from this problem, but it is perhaps a poor design to start with.

诺曼提出的"若要在函数式程序中新增一种事物,可能需要修改多个函数的定义,为其添加对应的新分支逻辑"这一观点,是否成立取决于函数式代码对类型类的运用是否得当。如果在整个代码库中,大量存在针对某一抽象数据类型的模式匹配操作,那么你确实会遇到这个问题,但这种情况本身就属于设计上的缺陷。

EDITED Removed reference to implicit conversions when discussing type classes. In Scala, type classes are encoded with implicit parameters, not conversions, although implicit conversions are another means to acheiving substitution of compatible types.
编辑说明 移除了讨论类型类时涉及的隐式转换相关内容。在 Scala 中,类型类是通过隐式参数来实现的,而非隐式转换,尽管隐式转换也是实现兼容类型替换的一种方式。

edited Feb 18, 2010 at 14:08

retronym

Comment

Zak

Typeclasses are not a mechanism for implicit conversion to other types. They're a description of a set of functions defined for a type so as to provide a form of polymorphism. The closest thing from Java-style OOP would be interfaces, though Haskell typeclasses have some important differences.

类型类并非实现隐式类型转换的机制。它是对为某一类型定义的函数集合的描述,其目的是实现一种多态性。在 Java 风格的面向对象编程中,与类型类最接近的概念是接口,但 Haskell 中的类型类与之存在一些重要区别。

  1. If you're in a heavily concurrent environment, then pure functional programming is useful. The lack of mutable state makes concurrency almost trivial. See Erlang.

    如果你处于高并发的开发环境中,那么纯函数式编程会是一个很好的选择。不可变状态的特性让并发编程的实现变得异常简单。可以参考 Erlang 语言的设计与实现。

  2. In a multiparadigm language, you may want to model some things functionally if the existence of mutable state is must an implementation detail, and thus FP is a good model for the problem domain. For example, see list comprehensions in Python or std.range in the D programming language. These are inspired by functional programming.

    在多范式语言中,如果可变状态的存在仅仅是一种实现细节,那么你可以采用函数式的方式对问题进行建模,此时函数式编程是适用于该问题领域的理想范式。例如,Python 中的列表推导式,以及 D 语言中的标准范围库,这些特性的设计都受到了函数式编程的启发。

answered Jan 16, 2010 at 21:41

dsimcha


函数式编程与面向对象编程:差异、应用场景及正交性

一、编程范式差异

(一)思想与状态管理

  • 面向对象编程(OOP):以对象为中心,将数据与操作数据的方法封装在一起,通过类的继承、多态等特性构建问题的层级化模型。其状态管理采用「原地修改」模式,允许对象内部状态可变,例如在类的方法中直接更新成员变量的值,类似填写纸质申请表时直接在原表上修改信息。
  • 函数式编程(FP):基于 lambda 演算,以函数为中心,强调数据流向而非控制流程。通过参数传递管理状态,避免副作用和变量赋值,推崇不可变性------即数据创建后不再修改,若需变更则生成新的数据副本,如同在申请表上覆盖透明薄膜记录变更,原表始终保持不变。

(二)语法与实现方式

  • OOP 依赖语句与表达式结合,常用循环、可变变量处理状态,例如通过循环遍历列表并累加求和,需维护中间变量的状态变化。
  • FP 仅使用表达式,通过递归、高阶函数等实现逻辑,求和等操作通过递归传递累加值完成,无中间变量修改。

(三)模块化实现逻辑

  • OOP 通过测试用例捕获对象行为,确保对象变更后仍符合预期,以此实现模块化。
  • FP 通过数学定律保障模块合规性,偏好通过逻辑证明验证代码正确性。

二、优缺点与适用场景

(一)面向对象编程(OOP)

  • 优势:擅长将复杂问题拆解为层级化对象模型,简化问题理解;当系统有固定操作集、需频繁新增「事物」(如新增业务实体类)时,可通过新增类实现扩展,无需修改现有代码。
  • 劣势:使用可变对象进行多线程编程时,需大量同步机制保障线程安全,大型应用中难以避免并发问题;当需新增操作时,可能需修改多个类的定义,违反「开闭原则」。
  • 适用场景:适合模拟现实世界实体、需求中「事物」类型频繁扩展的场景,如企业级业务系统、桌面应用程序等。

(二)函数式编程(FP)

  • 优势:不可变性使多线程并行处理更简单,无需担心变量被其他线程篡改;纯函数(无副作用)具备引用透明性,便于代码推理、测试和优化(如编译器可进行缓存、公共子表达式消除等);当系统有固定「事物」集、需频繁新增操作时,可通过新增函数扩展,不影响现有代码。
  • 劣势:对开发者思维模式要求较高,上手难度较大;完全无副作用的代码无法处理 I/O 等必须变更外部状态的操作,需通过特定机制(如 Haskell 的 STM monad)管理必要的副作用;新增「事物」类型时,可能需修改多个函数的模式匹配逻辑。
  • 适用场景:适合并发编程、符号数据处理、编译原理等场景,如编译器开发、大数据并行计算、多线程服务端程序等。

三、概念辨析

(一)副作用的争议与管理

  • 副作用指函数执行时除返回结果外,对外部环境的其他影响(如修改全局变量、I/O 操作、修改入参等)。FP 并非完全禁止副作用,而是主张限制并明确标识副作用,避免其分散在代码中导致逻辑混乱。
  • 副作用的危害:引入不可预测性,增加代码推理难度;导致函数依赖外部环境,难以单独测试和复用;多线程场景下需复杂同步机制。
  • 管理方式:OOP 通过封装减少副作用影响范围,FP 通过纯函数、monad 等机制隔离和控制副作用。

(二)FP 与 OOP 的正交性

  • 正交性指两个概念相互独立、互不排斥,可单独或组合使用。FP 侧重函数组合、不可变性、纯函数等特性,OOP 侧重封装、多态、抽象等特性,二者无本质冲突。
  • 实践体现:Scala、F# 等多范式语言同时支持两种编程风格,开发者可根据需求灵活选择------既可以用类封装数据和方法,又能使用不可变数据和高阶函数编写纯函数逻辑。
  • 典型示例:在 Scala 中,可定义不可变类(符合 FP 特性),同时通过继承实现多态(符合 OOP 特性);OCaml、Nemerle 等语言也实现了 OOP 与 FP 的融合。

四、软件演化中的表现

  • OOP 的演化优势:固定操作集、新增「事物」时,通过新增类实现扩展,现有类无需修改,适配如电商系统中新增商品类型的场景。
  • FP 的演化优势:固定「事物」集、新增操作时,通过新增函数实现扩展,现有函数保持不变,适配如编译器中新增代码优化规则的场景。
  • 共同挑战:当演化方向与范式优势相悖时(如 OOP 中新增操作、FP 中新增「事物」),会面临大量代码修改的问题,即 Phil Wadler 提出的「表达式问题」,目前尚无主流认可的完美解决方案。

五、总结

函数式编程与面向对象编程并非对立关系,而是各有侧重、可互补的编程范式。OOP 擅长构建结构化的实体模型,适配「事物」扩展频繁的场景;FP 擅长处理无状态逻辑和并发问题,适配操作扩展频繁的场景。

在实践中,无需严格割裂两种范式:现代多范式语言(如 C#、Python、Scala)已融合二者优势,开发者可采用「OOP 构建架构,FP 实现逻辑」的思路------用类封装实体和接口,用纯函数处理数据计算和业务逻辑,既保证系统的结构化和可读性,又提升代码的可测试性和并发安全性。学习两种范式的价值不仅在于掌握语法特性,更在于拓宽编程思维,根据具体问题选择最优的解决方案。



via

相关推荐
止观止2 个月前
C++20 Ranges:告别手写循环,像 SQL 一样操作数据
c++·stl·c++20·编程范式·ranges
窗户6 个月前
有限Abel群的结构(3)
python·抽象代数·编程范式
萤火架构2 年前
从新手到大师:四大编程范式解锁你的编码力!
函数式编程·面向对象编程·编程范式·声明式编程
华为云开发者联盟2 年前
3天上手Ascend C编程丨通过Ascend C编程范式实现一个算子实例
编程范式·算子