F#和继承的建模

use*_*784 7 polymorphism dsl inheritance f# functional-programming

我的问题涉及如何在F#中以功能方式处理继承.为了稍微描述一下,我举一个简单的例子.假设我们想要建立一个由各种动物组成的世界.每种动物都与其他种类共享一些属性(例如名称,大小等).此外,每种类型都可能有其他的,其他人不共享(例如,儿童的数量与狗和猫相关,但不适用于蜘蛛).此外,可能存在与每种动物类型相关联的方法或功能,其对于两种动物类型可能相同或不同,即存在可能对于特定种类而言过度的默认实施方式.每种动物类型可以具有仅针对该类型定义的方法.

现在,在OOP世界中,这可能会导致抽象类具有公共属性和抽象方法,后面是为每种动物类派生的类.我不确定如何在F#中功能性地指定域模型.这里: 在F#中使用哪些,抽象类或接口?声称"惯用的F#代码使用与C#不同的可扩展点(例如将函数/接口作为参数),因此您不需要抽象类".

如果这是应该采用的方式,是否可以提供一些基本的例子呢?

至于我对此的进一步思考,我认为属性应该封装在某种结构中.那么,F#中这方面的大多数惯用结构都是记录.这是否意味着存在父记录,该记录应包括在对应于特定"子"的其他记录中,即组成而不是继承.然而,在我看来,这是一种既不惯用也不特别优雅的解决方法.

我认为如何在F#中建模继承的首选方法是有区别的联合.但是,这并不能解决共享属性和方法的问题.

在我看来,与上述类似的模型非常频繁,因为它们隐含在大多数企业应用程序中.因此,是否有任何建议如何以功能方式处理(例如上述链接建议的方式或任何其他建议)?或者我们是否应该说这不是一个可以使用功能方法轻松建模的域名?

谢谢.

Tom*_*cek 9

您对该示例的描述已经预先假定了面向对象的编程模型.您正在以面向对象的术语描述问题,例如覆盖和为某些类型的动物定义的方法.这使得很难为您提供合理的替代功能表示,因为您的问题已经在答案中假定了面向对象的概念.

首先,当它们有意义时,在F#中使用面向对象的结构是完全没问题的(你的问题中的例子只是一个玩具样本,所以这可能是也可能不是这样).关键的想法是F#更喜欢组合而不是继承,因此您可能会尝试避免继承(这可能导致复杂的对象层次结构),而是从不同方面组成动物.

其次,如果您以不同的方式解释您的问题,那么使用受歧视的联合可能会有完美的功能表示.例如:

type MammalKind = Cat | Dog
type MammalInfo = { Legs : int; Children : int }

type Animal = 
  | Mammal of MammalKind * MammalInfo
  | Spider of (...)
Run Code Online (Sandbox Code Playgroud)

我们的想法是构建类型,以便不同种类的动物(您可以以不同的方式处理)具有自己的类型.例如,你可以编写一个函数,它接受MammalInfo并执行一些只对狗和猫有意义的计算(但不适用于蜘蛛).但正如我之前提到的,您对问题的描述本质上是面向对象的,因此可能很难看出如何做到这一点.

  • 关键问题是可扩展性——函数式方法(使用自由函数)使得在不改变类型定义的情况下更容易添加新操作;OO 方法可以更轻松地添加新的派生类,而无需修改现有函数(您只需实现所有虚拟方法)。在函数式风格中,人们通常更喜欢添加新函数的能力,但如果您有充分的理由认为您需要其他可扩展性,那么在 F# 中使用接口也是一个不错的选择。 (2认同)