10

我的问题与如何在 F# 中以功能方式处理继承有关。为了稍微描述一下,我举一个简单的例子。假设我们要模拟一个由各种动物组成的世界。每个动物种类与其他种类共享一些属性(例如名称、大小等)。此外,每一种都可能有其他的,它们不被其他人共享(例如,孩子的数量与狗和猫有关,但与蜘蛛无关)。此外,可能存在与每种动物种类相关联的方法或功能,它们对于两种动物种类可能相同也可能不同,即存在可以针对特定种类覆盖的默认实现。每种动物都可能具有仅为该种类定义的方法。

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

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

至于我对此的进一步思考,我认为应该将属性封装在某种结构中。然后,F#中这方面最惯用的结构是记录。这是否意味着要有一个父记录,该记录应包含在与特定“子”相对应的其他记录中,即组合而不是继承。然而,在我看来,这似乎是一种既不惯用也不特别优雅的解决方法。

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

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

谢谢你。

4

1 回答 1

13

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

首先,在 F# 中使用面向对象的构造是完全没问题的(您问题中的示例只是一个玩具示例,因此可能会或可能不会如此)。关键思想是 F# 更喜欢组合而不是继承,因此您可能会尝试避免继承(这会导致复杂的对象层次结构),而是从不同方面组合动物。

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

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

type Animal = 
  | Mammal of MammalKind * MammalInfo
  | Spider of (...)

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

于 2013-06-13T11:43:10.493 回答