FP和OO是正交的吗?

我已经一次又一次地听到了,我正试图理解和validationFP和OO是正交的。

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

FP鼓励尽可能的不变性和纯洁性,而OO似乎是为了状态和变异而build立的 – 一个稍微有组织的命令式编程版本? 我意识到对象可以是不可改变的,但是OO似乎意味着对我的状态/改变。

他们看起来像对立面。 这如何影响它们的正交性?

像Scala这样的语言可以很容易地做OO和FP,这是否会影响两种方法的正交性?

正交性意味着两件事情是不相关的。 它来自math,它意味着垂直 。 在通常的用法中,它可能意味着两个决定是不相关的,或者当考虑另一个主题时,一个主题是不相关的。 正如这里所使用的,正交意味着一个概念既不意味着也不排斥另一个。

面向对象编程和函数式编程这两个概念并不是不相容的。 面向对象并不意味着可变性。 许多被引入到面向对象程序的人通常首先使用C ++,Java,C#或类似的语言,这些语言在可变性是常见甚至是鼓励的情况下(标准库提供了供人们使用的可变类)。 因此,许多人将面向对象编程与命令式编程和可变性联系起来是可以理解的,因为这是他们如何学习的。

然而,面向对象的编程包含以下主题

  • 封装
  • 多态性
  • 抽象化

这并不意味着可变性,也不排除函数式编程。 所以是的,他们是正交的,他们是不同的概念。 他们不是对立的 – 你可以使用一个或另一个,或两者兼而有之(甚至两者都不)。 像Scala和F#这样的语言试图将这两种范式结合成一种语言:

Scala是一个多范式编程语言,旨在集成面向对象编程和函数式编程的特性

资源

F#是一个简洁,expression和高效的function面向对象的 .NET 语言 ,可以帮助您编写简单的代码来解决复杂的问题。

资源

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

这意味着他们不会互相影响。 也就是说,一个function性语言的function并不less,因为它也是面向对象的。

他们看起来像对立面。 它如何影响它们的正交性?

如果它们是对立的(即纯粹的function语言不可能是面向对象的),那么它们就不会是正交的。 但我不相信这是事实。

而面向对象似乎是为了状态和变异而build立起来的(一个有组织的版本的命令式编程?)。 而且我也意识到对象可以是不变的。 但是OO似乎意味着对我的状态/改变。

虽然大多数主streamOO语言都是如此,但是OO语言不需要具有可变状态。

如果一种语言具有对象,方法,虚拟inheritance和ad-hoc多态,那么它是一种面向对象的语言 – 不pipe它是否具有可变状态。

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

这意味着这两个概念没有对立的观点,也不是不相容的。

FP尽可能鼓励不变性和纯洁性。 而面向对象似乎是为了状态和变异而build立起来的(一个有组织的版本的命令式编程?)。 而且我意识到,对象可以是不可改变的。 但是OO似乎意味着对我的状态/改变。

他们看起来像对立面。 它如何影响它们的正交性?

像Scala这样的语言可以很容易地做OO和FP,这是否会影响这两种方法的正交性?

OO是关于封装,对象组成,数据抽象,通过子types的多态性,以及在必要时控制突变 (在OO中也鼓励不变性)。 FP是关于函数构成,控制抽象和约束多态性(aka参数多态性)的。 所以这两个想法并不矛盾。 它们都为您提供了不同的权力和抽象机制,当然可以用一种语言。 实际上,这是Scalabuild立的论点!

在Google的Scala实验演讲中,Martin Odersky很好地解释了他如何相信OO和FP这两个概念彼此正交,以及Scala如何将这两个范式优雅无缝地融合到一个在Scala社区中广为stream传的新范例中对象function范式。 一定要看你说话。 🙂


对象函数式语言的其他例子: OCaml , F# , Nemerle 。

对于两个概念是正交的,意味着它们可以独立地在任何给定的performanceforms中被实现。 例如,考虑音乐,你可以把音乐作品分类为它是多么和谐以及它是如何有节奏的。 “和谐”与“有节奏”这两个概念是正交的,即有谐和节奏,不和谐,有节奏的片断,还有和谐的节奏片断,还有和谐的节奏片断。

应用于原始问题意味着有纯粹的function性,非面向对象的编程语言,如Haskell,纯粹的面向对象,“非function性”语言(如Eiffel),还包括既不是C也不是语言的语言既如斯卡拉。

简而言之,Scala是面向对象的,意味着您可以定义数据结构(“类”和“特征”),它们使用操作这些数据的方法来封装数据,确保这些结构(“对象”)的实例始终处于定义的状态(对象的合同在同类中)。

另一方面,Scala是一个函数式语言,意味着它支持不可变而不可变的状态,并且函数是第一类对象,可以像任何其他对象一样用作局部variables,字段或其他函数的参数。 除此之外,几乎Scala中的每个语句都有一个值,它鼓励您使用函数式编程风格。

面向对象编程和函数式编程的正交性,意味着作为程序员,您可以自由select您认为适合您的目的的这两个概念的任意组合。 你可以用纯粹的命令式编写你的程序,只使用可变对象而不使用函数作为对象,另一方面,你也可以在Scala中编写纯粹的函数式程序,而不使用任何面向对象的特性。

斯卡拉真的不需要你使用一种风格或其他。 它可以让你select两全其美的解决你的问题。

像所有的分类一样,编程语言分为function性,面向对象,程序性等是虚构的。 但是我们确实需要分类,而在编程语言中,我们用一组语言特征和那些使用这种语言(后者受前者影响的)的哲学方法进行分类。

所以有时“面向对象”语言可以成功地采用“function”编程语言的特征和哲学,反之亦然。 但是,并不是所有的编程语言特性和哲学都是兼容的。

例如,像OCaml这样的函数式语言通过词法范围和闭包完成封装,而面向对象的语言则使用公共/私有访问修饰符。 这些并不是不兼容的机制,但是它们是多余的,像F#这样的语言(一种大多数function性的语言,试图与明确的面向对象的.NET库和语言栈协调一致)必须尽量长差距。

作为另一个例子,OCaml使用结构types系统来实现面向对象,而大多数面向对象语言使用标准types系统。 这些非常不兼容,有趣的是代表了面向对象语言领域的不兼容性。

对象的概念可以以不可变的方式实现。 一个例子是Abadi和Cardelli所着的“ 对象理论 ” 一书,其目的在于将这些想法forms化,并且首先给予对象不可变的语义,因为这使得面向对象程序的推理变得更简单。

在这种情况下,传统上将对象就地修改的方法返回一个新的对象,而前一个对象仍然存在。

您可以将函数作为对象和对象实现为函数的集合,因此这两个概念之间显然存在某种关系。

FP尽可能鼓励不变性和纯洁性

你正在谈论纯粹的function性编程。

而OO似乎是为了状态和变异而build立的

没有要求对象是可变的。 我会说对象和变异是正交的概念。 例如,OCaml编程语言为纯function对象更新提供了语法。

像Scala这样的语言可以使OO和FP都变得很容易

不是真的。 缺less尾部调用优化意味着大部分惯用的纯函数代码将在Scala中堆栈溢出,因为它会泄漏堆栈帧。 例如, 延续传球风格 (CPS)以及本文中所描述的所有技术都由布鲁斯·麦克亚当(Bruce McAdam)来包装 。 有没有简单的方法来解决这个问题,因为JVM本身不能进行尾部呼叫优化。

关于纯函数式编程和面向对象编程的正交性,我会说他们至less接近于正交,因为纯粹的函数式编程只处理小的程序(例如高阶函数),而面向对象的编程则处理大的规模结构的程序。 这就是为什么函数式编程语言通常为大规模结构提供一些其他机制的原因,例如Standard ML和OCaml的高阶模块系统,或Common Lisp的CLOS或Haskell的types类。

有一件事帮助我了解FP和OO之间的关系,就是SICP的书,尤其是“function程序的模块化和对象的模块化”一节。如果你正在考虑这些问题,并且你有一个闲暇的周末,可能值得通读前三章,它的漂亮的眼睛开放。

我刚刚find了OOP和FP的正交性的一个很好的解释 。

基本思路如下。 想象一下,我们正在使用mathexpression式的AST。 所以我们有不同types的名词(常量,加法,乘法)和不同的动词(eval,toString)。

比方说,expression式是(1 + 2) * 3 。 那么AST就是:

       乘法
          / \
     另外3
       / \
      1 2

为了实现一个动词,我们必须为每个types的名词提供它的实现。 我们可以把它表示为一张表格:

  +---------------------+-------------------------------------+ | eval | toString | +---------------+---------------------+-------------------------------------+ | constant | value | value.toString | +---------------+---------------------+-------------------------------------+ | addition | lhs.eval + rhs.eval | lhs.toString + " + " + rhs.toString | +---------------+---------------------+-------------------------------------+ | mutiplication | lhs.eval * rhs.eval | lhs.toString + " * " + rhs.toString | +---------------+---------------------+-------------------------------------+ 

“正交性”来自于事实,而不是在OOP中,我们将逐行实现这个表格:我们将把每一个名词都表示为一个类,它将必须实现每一种方法。

另一方面,在FP中 ,我们将按实现这个表 – 我们将为每个动词写一个函数,并且这个函数对不同types的参数(可能使用模式匹配)会有不同的反应。

正交。 这听起来不错。 如果你受过教育,你可以带一点点,假装。 它有点像范例。

这一切都取决于你在哪个圈子里,以及每种编程技术会给你什么。 我已经阅读了一些关于SS的文章,大部分来自函数式编程语言的人都坚持这样一个事实,即只能运行,而其他任何事情都与思维和思维方式背道而驰。

面向对象的编程主要是捕获状态,并保持这个状态尽可能地本地化,以免受到不属于你pipe理状态的对象的任何东西的影响。 另一方面,函数式编程从不同的angular度来看待状态问题,试图将状态从系统中分离出来,并将其简化为function。 是的,你可以在你的代码中使用这两种技术,但他们都从不同的angular度来看待软件的devise。

function编程技术引起了人们极大的兴趣,主要是因为在处理多核芯片和并行编程时需要对状态进行pipe理。 看来在这个时候,函数式编程确实在处理这个问题时占了上风,然而使用对象可以达到相同的效果。 你只是想着不同的问题。 不要搔头,尽可能地摆脱状态,而是看devise中的物体,看看如何使用devise模式,循环冗余校验和对象分析。 虽然对象自己进入,但function编程更困难的是分析现实世界并将其映射到可理解的计算机化系统。 例如,在面向对象的情况下,一个人的对象就是一个对状态进行处理的方法的封装。 在函数式编程中,一个人将被分解成数据部分和作用于个人数据的函数,附加条件是数据应该只被创build一次而且是不变的。

我必须承认,虽然来自OO的背景,但是在处理多核芯片时,大多数OO语言中,我已经走了function路线,主要是由核心编程devise结构(如线程和委托)以及传递伪数据对象。 这引起了我对OO编程技术的质疑,因为它似乎没有很好地映射到这个线程化devise。