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

到目前为止,我主要接触了面向对象编程,并期待学习一门函数式语言。我的问题是:

  • 你什么时候选择函数式编程而不是面向对象?
  • 函数式编程是更好的选择的典型问题定义是什么?
293116 次浏览

您不必在这两种范式之间做出选择。您可以使用许多功能概念编写具有OO架构的软件。FP和OOP本质上是正交的

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

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

许多现代语言是多范式的。

推荐阅读

由于我在同一条船上(OOP背景,学习FP),我建议你一些我非常欣赏的读物:

  • 日常. NET开发的函数式编程,作者Jeremy Miller。这是一篇很棒的文章(尽管格式很差),展示了许多技术和C#上FP的实用、真实示例。

  • 真实世界函数式编程,Tomas Petricek著。一本主要涉及FP概念的好书,试图解释它们是什么,何时应该使用它们。F#和C#中都有很多例子。此外,Petricek的博客是一个很好的信息来源。

  1. 如果您处于重并发环境中,那么纯函数式编程很有用。缺乏可变状态使得并发几乎微不足道。请参阅Erlang。

  2. 在多范式语言中,如果可变状态的存在是必须的实现细节,你可能希望在功能上建模一些东西,因此FP是问题域的一个很好的模型。例如,请参阅Python中的列表理解或D编程语言中的std.range。这些都是受函数式编程的启发。

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

当您预测到一种不同类型的软件演进时:

  • 当你对事物有一组固定的操作时,面向对象语言很好,并且随着代码的发展,你主要添加新事物。这可以通过添加实现现有方法的新类来实现,并且现有类不受影响。

  • 当你有一组固定的事物时,函数式语言是很好的,随着代码的发展,你主要是在现有事物上添加新的操作。这可以通过添加使用存量数据类型计算的新函数来实现,并且现有函数不受影响。

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

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

  • 向函数式程序添加一种新事物可能需要编辑许多函数定义以添加新案例。

这个问题已经众所周知很多年了;在1998年,Phil Wadler称之为“表达问题”.尽管一些研究人员认为表达问题可以用诸如混合语言这样的语言特征来解决,但一个被广泛接受的解决方案尚未成为主流。

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

函数式语言擅长以树形式操作符号数据。一个最受欢迎的例子是编译器,其中源语言和中间语言很少变化(大部分是相同的事情),但编译器编写者总是添加新的翻译和代码改进或优化(对事物的新操作)。更普遍的是,编译和翻译是函数式语言的“杀手级应用”。

面向对象编程提供:

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

函数式编程,在Haskell甚至Scala中,可以通过类型类的更通用机制允许替换。不鼓励或禁止可变的内部状态。也可以实现内部表示的封装。参见Haskell vs OOP以获得很好的比较。

诺曼的断言“向函数式程序添加一种新的东西可能需要编辑许多函数定义来添加一个新案例”取决于函数式代码使用类型类的程度。如果特定抽象数据类型的模式匹配分布在整个代码库中,你确实会遇到这个问题,但这可能是一个糟糕的设计。

编辑在讨论类型类时删除了对隐式转换的引用。在Scala中,类型类是用隐式参数编码的,而不是转换,尽管隐式转换是实现兼容类型替换的另一种手段。