使用函数式编程样式数据类型进行模型继承

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用函数式编程样式数据类型进行模型继承相关的知识,希望对你有一定的参考价值。

我最近一直在使用F#并尝试以功能方式编写代码,而不是在不同的语法中再次使用OOP。我现在遇到了一个问题,我可以通过混合继承和有区别的联合来解决这个问题,但我正试图找到一个纯粹的功能样式表示。

我想要建模的是这样的(改为保留模式,因为我不能使用实际的代码):

type Shape =
    | Rectangle of Size * Size
    | Circle of Diameter

到目前为止这么好,但现在我需要代表一组与不同类型的形状相关的其他属性,例如:

type ShapeProperty =
    | Color of Shape * Color // Fine, valid for all shapes
    | Rotation of Shape * Angle // Wants to be Rotation of Rectangle * Angle
    | Details of Shape * int // Wants to be Detail of Circle * int

如果不使用Shape的区别联合,我使用了基类和继承,我可以参考实际类型并确保Rotation只能应用于Rectangle而不是Circle,但现在我不能。有没有办法实现类似的东西,同时仍然保持纯粹的功能数据结构?

编辑:

我目前的解决方案是将单个形状的定义与形状完全相关的事实分开,如下所示:

type Rectangle = Rectangle of Size * Size // Or using a record type
type Circle = Circle of Diameter // Or using a record type
type Shape = RectangleShape of Rectangle | CircleShape of Circle

这意味着我有在ShapeProperty中引用的类型:

type ShapeProperty =
    | Color of Shape * Color
    | Rotation of Rectangle * Angle
    | Details of Circle * int

这感觉有点笨拙,因为现在需要封装Shape类型中的每个形状以将它们存储在一个集合中,但它确实给了我一种表达我所追求的类型安全性的方法。任何改进都会受到欢迎。

答案

我认为受歧视的工会可能只是这部分工作的错误工具。仅仅因为你在编写功能代码并不意味着你应该抛弃你所知道的一切。

受歧视的联合(在某些方面,并且有一点需要注意)继承的反转(派生类型),我们可以称它们为组合类型。

在派生类型模型中,关于父级的所有内容都保证对于子级(LSP)是真实的,在这个组合类型模型中,关于子级的所有内容都保证对父级是真实的。(即代替“新狗:动物,新猫” :动物,它是新的狗,猫:CatDog,所以你得到了关于猫和狗的所有陈述的新结构。把它想象成猫和狗的所有陈述的交集。)

那么问题就变成了,“我们如何使用OCaml中的派生类型?”好吧,那里的“O”代表对象......

我建议你为你的形状heiarchy创建一个派生类型的对象模型,因为你有一个顶部类型(形状)和一个底部类型(空形状,或null)。然后你用这些物体组成你的ADT,所以你有

抽象的形状,圆形:形状,矩形:形状,

那你有

类型ShapeProperty = | Foo of Shape |矩形条| Blah of Circle ;;

任何了解形状属性的东西都必须能够处理所有这三种情况(合理的,因为这就是你所拥有的),圆形和矩形的分配与形状兼容,所以你不必担心装箱惯例。

对于它的价值,YMMV等Haskell(另一个主要的ML方言运行)不使用派生类型的对象,它使用所谓的“类型类”,它是你“派生自”的属性/行为的集合。并“保证实现”,从而允许函数接受类型类的具体实例。

虽然在它的哲学中功能更强大,但试图找出正在发生的事情让我头疼,因为我用于对象类似结构的传统抽象不再适用,我必须使用逻辑等效的这些结构,但在语义上更加不寻常(虽然我知道很多人使用它们取得了巨大的成功,但它可能只是我自己的失败)。

请注意,由于已标记的联合已被标记,因此您需要做的就是保证所有标记的语义操作。那个动作可能是“失败的'为什么你给我其中一个,我不知道该怎么办'”。你注意到这个结构的问题是你在这样做时失去了许多非常酷的类型安全方面。例如,你编写一个接受int选项的函数,然后如果该选项什么都没有你抛出异常,那么,为什么你说你知道如何处理一个选项int?

以上是关于使用函数式编程样式数据类型进行模型继承的主要内容,如果未能解决你的问题,请参考以下文章

大数据之MapReduce分布编程模型之函数式编程范式

函数式编程

函数式编程之-F#类型系统

MapReduce分布编程模型之函数式编程范式

Rails 类型的 webapp 中的“模型”如何用函数式编程语言实现?

Java8函数式编程的宏观总结