在多年的OO编程中,我了解了区别工会是什么,但我从未真正错过过他们。我最近一直在用C#进行一些函数式编程,现在我一直希望自己拥有它们。这让我感到困惑,因为从表面上看,区别工会的概念似乎与功能/ OO二分法完全无关。
函数式编程中是否有固有的功能,使有区别的联合比在OO中更有用,或者是通过强迫自己以“更好”的方式分析问题,我只是提高了标准,现在要求更好模型?
在多年的OO编程中,我了解了区别工会是什么,但我从未真正错过过他们。我最近一直在用C#进行一些函数式编程,现在我一直希望自己拥有它们。这让我感到困惑,因为从表面上看,区别工会的概念似乎与功能/ OO二分法完全无关。
函数式编程中是否有固有的功能,使有区别的联合比在OO中更有用,或者是通过强迫自己以“更好”的方式分析问题,我只是提高了标准,现在要求更好模型?
Answers:
区别联合确实与模式匹配结合在一起,您可以根据情况选择不同的行为。但是,这种模式从根本上与纯粹的OO原理相反。
在纯OO中,行为差异应由类型(对象)本身定义并封装。因此,等同于模式匹配的方法是在对象本身上调用单个方法,然后该方法将由有问题的子类型重载以定义不同的行为。从外部检查对象的类型(模式匹配所做的工作)被视为反模式。
根本的区别是数据和行为在函数式编程中是分开的,而数据和行为则封装在OO中。
这是历史原因。通过合并越来越多的功能,像C#这样的语言正从经典的OO语言发展为多范式语言。
List<A>
该方法是B Match<B>(B nil, Func<A,List<A>,B> cons)
。例如,这正是Smalltalk用于布尔值的模式。基本上,这也是Scala处理它的方式。使用多个类是不需要公开的实现细节。
isEmpty
方法来检查对下一个节点的引用是否为空。
OO中经常使用的命令式编程技术通常依赖于两种模式:
null
以指示“无值”或失败。功能范例通常避免这两种情况,而是返回表示成功/失败原因或值/无值的复合类型。
受歧视的工会适合这些化合物类型。例如,在第一个实例中,您可能返回true
或描述失败的某些数据结构。在第二种情况下,包含值或的联合none
,nil
等等。第二种情况非常普遍,以至于许多功能语言都内置了表示该值/无联合的“也许”或“选项”类型。
当使用例如C#转换为功能样式时,您会很快发现对这些复合类型的需求。void/throw
而null
就是不正确的使用这种代码感觉。歧视工会(DU)非常适合该法案。因此,就像我们很多人一样,您发现自己想要它们。
好消息是,那里有很多库可以在C#中模拟DU(例如,看看我自己的Succinc <T>库)。
在主流OO语言中,求和类型通常不太有用,因为它们正在解决与OO子类型化类似的问题。看它们的一种方法是它们都处理子类型,但是OO是open
即可以将任意子类型添加到父类型,而求和类型是closed
即先确定哪些子类型有效。
现在,许多OO语言将子类型与其他概念(例如继承的结构,多态性,引用类型等)组合在一起,以使它们通常更有用。结果是,它们往往需要更多的工作(使用类和构造函数以及诸如此类的东西)来进行设置,因此在通用类型化变得普遍之前,它们往往不会用于Result
s和Option
s之类的东西。
我还要说的是,大多数人在开始进行OO编程时就了解了现实世界中的关系,例如Dog isa Animal,这意味着Integer isa Result或Error isa Result似乎有些陌生。虽然想法很相似。
至于为什么功能语言可能更喜欢封闭式而不是开放式,可能的原因之一是它们倾向于使用模式匹配。这对于函数多态性很有用,但对于封闭类型也非常有效,因为编译器可以静态检查匹配项是否覆盖所有子类型。尽管我不相信有任何内在的好处(这可能会误解),但是这可以使语言更加一致。
sealed
表示“只能在同一编译单元中扩展”,这使您可以在设计时关闭子类集。
斯威夫特乐于使用区分性联合,但称其为“枚举”。枚举是Swift中对象的五个基本类别之一,它们是类,结构,枚举,元组和闭包。Swift可选变量是可区分联合的枚举,它们对于任何Swift代码都是绝对必要的。
因此,“区分联合与函数式编程相关联”的前提是错误的。