纯函数式编程上下文中的面向对象编程? [英] Object-oriented programming in a purely functional programming context?

查看:19
本文介绍了纯函数式编程上下文中的面向对象编程?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在函数式编程 (FP) 上下文中使用面向对象编程 (OOP) 有什么优势吗?

Are there any advantages to using object-oriented programming (OOP) in a functional programming (FP) context?

我已经使用 F# 有一段时间了,我注意到我的函数越是无状态,我就越不需要将它们作为对象的方法.特别是,依靠类型推断使其在尽可能多的情况下可用是有好处的.

I have been using F# for some time now, and I noticed that the more my functions are stateless, the less I need to have them as methods of objects. In particular, there are advantages to relying on type inference to have them usable in as wide a number of situations as possible.

这并不排除需要某种形式的命名空间,这与 OOP 是正交的.也不鼓励使用数据结构.事实上,真正使用 FP 语言很大程度上依赖于数据结构.如果您查看在 F Sharp Programming/Advanced Data Structures 中实现的 F# 堆栈,你会发现它不是面向对象的.

This does not preclude the need for namespaces of some form, which is orthogonal to being OOP. Nor is the use of data structures discouraged. In fact, real use of FP languages depend heavily on data structures. If you look at the F# stack implemented in F Sharp Programming/Advanced Data Structures, you will find that it is not object-oriented.

在我看来,OOP 与具有主要作用于对象状态的方法密切相关,以改变对象.在不需要也不希望的纯 FP 上下文中.

In my mind, OOP is heavily associated with having methods that act on the state of the object mostly to mutate the object. In a pure FP context that is not needed nor desired.

一个实际的原因可能是能够与 OOP 代码交互,这与 F# 与 .NET.然而,除此之外,还有什么原因吗?在 Haskell 世界,编程更纯粹的 FP 是什么体验?

A practical reason may be to be able to interact with OOP code, in much the same way F# works with .NET. Other than that however, are there any reasons? And what is the experience in the Haskell world, where programming is more pure FP?

我将感谢任何有关该问题的论文或反事实真实世界示例的参考.

I will appreciate any references to papers or counterfactual real world examples on the issue.

推荐答案

您看到的脱节不是 FP 与 OOP.它主要是关于不变性和数学形式主义与可变性和非正式方法.

The disconnect you see is not of FP vs. OOP. It's mostly about immutability and mathematical formalisms vs. mutability and informal approaches.

首先,让我们放弃可变性问题:您可以拥有具有可变性的 FP 和具有不变性的 OOP.甚至比你更实用的 Haskell 可以让你随心所欲地使用可变数据,你只需要明确什么是可变的以及事情发生的顺序;撇开效率问题不谈,几乎任何可变对象都可以构造并返回一个新的、更新的"实例,而不是改变其自身的内部状态.

First, let's dispense with the mutability issue: you can have FP with mutability and OOP with immutability just fine. Even more-functional-than-thou Haskell lets you play with mutable data all you want, you just have to be explicit about what is mutable and the order in which things happen; and efficiency concerns aside, almost any mutable object could construct and return a new, "updated" instance instead of changing its own internal state.

这里更大的问题是数学形式主义,特别是在一种几乎没有从 lambda 演算中移除的语言中大量使用代数数据类型.您已经用 Haskell 和 F# 标记了它,但意识到这只是函数式编程领域的一半;与 ML 风格的语言相比,Lisp 家族有一个非常不同的、更随心所欲的特性.今天广泛使用的大多数面向对象系统本质上都是非常非正式的——面向对象确实存在形式主义,但它们并没有像 ML 风格的语言中的 FP 形式主义那样被明确地调用.

The bigger issue here is mathematical formalisms, in particular heavy use of algebraic data types in a language little removed from lambda calculus. You've tagged this with Haskell and F#, but realize that's only half of the functional programming universe; the Lisp family has a very different, much more freewheeling character compared to ML-style languages. Most OO systems in wide use today are very informal in nature--formalisms do exist for OO but they're not called out explicitly the way FP formalisms are in ML-style languages.

如果消除形式主义不匹配,许多明显的冲突就会消失.想要在 Lisp 之上构建一个灵活的、动态的、特别的 OO 系统吗?继续吧,它会工作得很好.想要为 ML 风格的语言添加一个正式的、不可变的 OO 系统吗?没问题,只是不要指望它与 .NET 或 Java 配合得很好.

Many of the apparent conflicts simply disappear if you remove the formalism mismatch. Want to build a flexible, dynamic, ad-hoc OO system on top of a Lisp? Go ahead, it'll work just fine. Want to add a formalized, immutable OO system to an ML-style language? No problem, just don't expect it to play nicely with .NET or Java.

现在,您可能想知道, 什么是 OOP 的合适形式?好吧,这是一个妙语:在很多方面,它比 ML 风格的 FP 更以功能为中心!我将参考我最喜欢的论文之一,以了解似乎是关键区别的内容:结构化数据,如 ML 风格语言中的代数数据类型,提供了数据的具体表示和定义操作的能力;对象提供了对行为的黑盒抽象,并且能够轻松替换组件.

Now, you may be wondering, what is an appropriate formalism for OOP? Well, here's the punch line: In many ways, it's more function-centric than ML-style FP! I'll refer back to one of my favorite papers for what seems to be the key distinction: structured data like algebraic data types in ML-style languages provide a concrete representation of the data and the ability to define operations on it; objects provide a black-box abstraction over behavior and the ability to easily replace components.

这里有一个比 FP 与 OOP 更深入的二元性:它与一些编程语言理论家所说的表达式问题:对于具体的数据,您可以轻松地添加与之相关的新操作,但更改数据的结构更加困难.使用对象,您可以轻松添加新数据(例如,新子类),但添加新操作很困难(想想向具有许多后代的基类添加新抽象方法).

There's a duality here that goes deeper than just FP vs. OOP: It's closely related to what some programming language theorists call the Expression Problem: With concrete data, you can easily add new operations that work with it, but changing the data's structure is more difficult. With objects you can easily add new data (e.g., new subclasses) but adding new operations is difficult (think adding a new abstract method to a base class with many descendants).

我之所以说 OOP 更以函数为中心,是因为函数本身代表了一种行为抽象形式.事实上,你可以在 Haskell 之类的东西中模拟 OO 风格的结构,方法是使用包含一堆函数的记录作为对象,让记录类型成为各种接口"或抽象基类",并让创建记录的函数替换类构造函数.因此,从这个意义上说,OO 语言使用高阶函数的频率远远超过 Haskell 等.

The reason why I say that OOP is more function-centric is that functions themselves represent a form of behavioral abstraction. In fact, you can simulate OO-style structure in something like Haskell by using records holding a bunch of functions as objects, letting the record type be an "interface" or "abstract base class" of sorts, and having functions that create records replace class constructors. So in that sense, OO languages use higher-order functions far, far more often than, say, Haskell would.

有关此类设计在 Haskell 中实际得到很好使用的示例,请阅读 graphics-drawingcombinators 包,特别是它使用包含函数的不透明记录类型并仅根据它们的行为组合事物的方式.

For an example of something like this type of design actually put to very nice use in Haskell, read the source for the graphics-drawingcombinators package, in particular the way that it uses an opaque record type containing functions and combines things only in terms of their behavior.

我忘记在上面提到的最后几件事.

A few final things I forgot to mention above.

如果 OO 确实广泛使用了高阶函数,那么乍一看,它似乎应该很自然地适合 Haskell 等函数式语言.不幸的是,情况并非如此.确实,对象正如我所描述的(参见 LtU 链接中提到的论文)非常适合.事实上,结果是一种比大多数 OO 语言更纯粹的 OO 风格,因为私有成员"由用于构造对象"的闭包隐藏的值表示,并且除了一个特定实例本身之外,其他任何东西都无法访问.没有比这更私密的了!

If OO indeed makes extensive use of higher-order functions, it might at first seem that it should fit very naturally into a functional language such as Haskell. Unfortunately this isn't quite the case. It is true that objects as I described them (cf. the paper mentioned in the LtU link) fit just fine. in fact, the result is a more pure OO style than most OO languages, because "private members" are represented by values hidden by the closure used to construct the "object" and are inaccessible to anything other than the one specific instance itself. You don't get much more private than that!

在 Haskell 中效果不佳的是子类型.而且,虽然我认为继承和子类型在面向对象语言中经常被误用,但某种形式的子类型对于能够以灵活的方式组合对象非常有用.Haskell 缺乏子类型的固有概念,并且手动替换使用起来往往非常笨拙.

What doesn't work very well in Haskell is subtyping. And, although I think inheritance and subtyping are all too often misused in OO languages, some form of subtyping is quite useful for being able to combine objects in flexible ways. Haskell lacks an inherent notion of subtyping, and hand-rolled replacements tend to be exceedingly clumsy to work with.

顺便说一句,大多数具有静态类型系统的 OO 语言也会对子类型进行完整的散列,因为可替换性过于宽松,并且没有为方法签名的变化提供适当的支持.事实上,我认为唯一没有完全搞砸的成熟的 OO 语言,至少我知道,是 Scala(F# 似乎对 .NET 做出了太多让步,但至少我不认为它会犯任何错误).不过,我对许多此类语言的经验有限,所以我在这里肯定是错的.

As an aside, most OO languages with static type systems make a complete hash of subtyping as well by being too lax with substitutability and not providing proper support for variance in method signatures. In fact, I think the only full-blown OO language that hasn't screwed it up completely, at least that I know of, is Scala (F# seemed to make too many concessions to .NET, though at least I don't think it makes any new mistakes). I have limited experience with many such languages, though, so I could definitely be wrong here.

在特定于 Haskell 的注释中,它的类型类"通常对面向对象的程序员来说很有吸引力,我要说的是:不要去那里.试图以这种方式实现 OOP 只会流泪.将类型类视为重载函数/运算符的替代品,而不是 OOP.

On a Haskell-specific note, its "type classes" often look tempting to OO programmers, to which I say: Don't go there. Trying to implement OOP that way will only end in tears. Think of type classes as a replacement for overloaded functions/operators, not OOP.

这篇关于纯函数式编程上下文中的面向对象编程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆