功能编程与面向对象编程

Oli*_*nde 763 oop paradigms functional-programming

到目前为止,我已经主要接触过OO编程,并期待学习一门函数式语言.我的问题是:

  • 什么时候选择面向对象的函数式编程?
  • 什么是典型的问题定义,函数式编程是更好的选择?

Nor*_*sey 1170

什么时候选择面向对象的函数式编程?

当您预期不同类型的软件演变时:

  • 当你对事物有一套固定的操作时,面向对象的语言是很好的,随着代码的发展,你主要添加新东西.这可以通过添加实现现有方法的新类来完成,并且现有类保持不变.

  • 当你有一套固定的东西时,函数式语言是很好的 ,随着代码的发展,你主要在现有的东西上添加新的操作.这可以通过添加使用现有数据类型计算的新函数来实现,并且现有函数是独立的.

当进化走错路时,你会遇到问题:

  • 向面向对象的程序添加新操作可能需要编辑许多类定义以添加新方法.

  • 在功能程序中添加新类型的东西可能需要编辑许多函数定义来添加新案例.

这个问题多年来一直众所周知; 1998年,Phil Wadler将其称为"表达问题".虽然一些研究人员认为表达问题可以通过mixins这样的语言特性来解决,但是一种被广泛接受的解决方案尚未成为主流.

什么是典型的问题定义,函数式编程是更好的选择?

功能语言擅长以树形式操纵符号数据.最喜欢的例子就是编译器,在源和中间语言改变很少(几乎相同的事情),但是编译器作者一直在增加新的翻译和代码改进或优化(对事物的新操作).编译和翻译更一般地是功能语言的"杀手级应用".

  • 这个答案背后有一些严重的禅.我认为它说明了某些OOP设计模式(访问者)实际上是黑客的事实,它试图克服添加新操作的问题. (115认同)
  • @ErikReppen问题何时出现,何时选择使用功能特性,何时选择使用面向对象的功能? (58认同)
  • 在JavaScript中,您可以拥有所有这些东西. (53认同)
  • @NormanRamsey:非常好的答案,与SICP一致.根据这种分类,功能和程序编程在面向对象编程的相反方面组合在一起.这可以解释1980年代后期OOP在20世纪90年代早期的热潮:当GUI成为主流时,OOP被证明是一种很好的建模方法,因为你通常有一套固定的操作(绘画,打开,关闭,调整大小)以及越来越多的小部件.当然,这并不意味着OOP比任何应用程序都要好,如图所示. (9认同)
  • @NormanRamsey在JS中混合起来并不常见,而且一流的功能与许多JS OOP相关的功能有关.JS的数组排序将函数作为一个arg,可以产生一些强大的数据结构.Closures +一个传递函数用于保持jquery对象非常轻量级的内存,因为大多数方法只是引用.等等... (7认同)
  • @bigcodeszzer “糟糕的设计”,也许,但语言,而不是应用程序。这里有一个关于这个问题的有趣讨论,通常称为“表达式问题”,以及如何使用通常在面向对象和函数式语言中都没有但在 Closure 等混合语言中存在的语言特性来解决它。http://eli.thegreenplace.net/2016/the-expression-problem-and-its-solutions/ (2认同)

Bru*_*eis 173

您不一定要在两种范例之间进行选择.您可以使用许多功能概念编写具有OO架构的软件.FP和OOP本质上是正交的.

以C#为例.你可以说它主要是OOP,但有许多FP概念和结构.如果考虑Linq,允许Linq存在的最重要的构造本质上是功能性的:lambda表达式.

另一个例子,F#.你可以说它主要是FP,但有许多OOP概念和结构可用.您可以定义类,抽象类,接口,处理继承.您甚至可以在使代码更清晰或显着提高性能时使用可变性.

许多现代语言都是多范式的.

推荐读物

因为我在同一条船上(OOP背景,学习FP),我建议你读一些我真的很感激:

  • @duffymo:你的评论,你提出的方式,大多没有意义.没有人想要比较语言,虚拟机或平台,谢谢. (8认同)
  • @Bruno - 对".NET的力量"的回应.放松. (6认同)
  • 有趣的是,我没有看到你谴责Dykam关于他毫无意义的评论.你在我不看的时候被提名为主持人吗?除了你,没有人会在这里燃烧.我会再说一遍 - 放松一下. (6认同)
  • @nawfal,直到你可以指出两种范式中的某些内在特征并说它们是不相容的,它们是正交的:这是讨论的核心.根据定义,FP与命令式编程不兼容,但OOP不仅限于命令式编程.我们对这些概念有不同用语的原因是我们可以谈论它们:当你把它们混在一起时,你只是迫使我们不必要地拿出新词. (5认同)
  • 嘿,对不起,如果我开始发火.我并不是说其他​​平台不那么强大,只是.NET不仅支持OOP.例如,它具有尾调用优化. (4认同)
  • 我不认为FP和OOP是正交的.使用功能构造与函数式编程不同.当然在Linq中使用像lambdas这样的函数结构会使它更少OO,但它仍然不是函数式编程.FP是函数是一等公民的地方,当OOP是类是第一类构建块时(或者那种效果 - 我确实知道有很多种OOP).Imo,正确的措辞是"有多种范式的语言可以让你编写OOP结构以及FP结构,从而在过程中减少OOP和更少的FP". (3认同)

ret*_*nym 31

面向对象编程提供:

  1. 封装,到
    • 控制内部状态的突变
    • 限制耦合到内部表示
  2. 子类型,允许:
    • 替换兼容类型(多态)
    • 在类之间共享实现的粗略方法(实现继承)

Haskell甚至Scala中的函数式编程可以允许通过类型类的更通用机制进行替换.不鼓励或禁止可变的内部状态.还可以实现内部表示的封装.有关比较,请参阅Haskell与OOP.

Norman断言"在功能程序中添加新东西可能需要编辑许多函数定义来添加新案例".取决于功能代码使用类型类的程度.如果特定抽象数据类型上的模式匹配遍布整个代码库,您确实会遇到这个问题,但它可能是一个糟糕的设计.

EDITED在讨论类型类时删除了对隐式转换的引用.在Scala中,类型类使用隐式参数进行编码,而不是转换,尽管隐式转换是实现兼容类型替换的另一种方法.

  • 类型类不是隐式转换为其他类型的机制.它们是为一个类型定义的一组函数的描述,以便提供一种多态的形式.与Java风格的OOP最接近的是接口,尽管Haskell类型类有一些重要的区别. (3认同)

dsi*_*cha 24

  1. 如果您处于高度并发的环境中,那么纯函数式编程就很有用.缺乏可变状态使得并发几乎是微不足道的.见Erlang.

  2. 在多范式语言中,如果可变状态的存在必须是实现细节,您可能希望在功能上对某些事物进行建模,因此FP是问题域的良好模型.例如,请参阅D编程语言中的Python或std.range中的列表推导.这些都受到函数式编程的启发.