当前位置: 首页 > 知识库问答 >
问题:

在Haskell中,为什么有typeclass层次结构/继承?

鲜于念
2023-03-14

为了澄清我的问题,让我用一种或多或少相同的方式重新措辞:

为什么Haskell中有超类/类继承的概念?导致这种设计选择的历史原因是什么?例如,为什么有一个没有类层次结构的基库,只有相互独立的类型库是如此糟糕?

此外,我在类继承中看到的一个可能不太好的事情是:我认为一个类实例会默默地选择一个对应的超类实例,这可能是为该类型实现的最自然的实例。让我们把单子看作函子的子类。也许可以有不止一种方法来定义某个类型的函子,它也碰巧是一个单子。但是,说一个单子是一个函子,就隐含地为那个单子选择了一个特定的函子。有一天,你可能会忘记你实际上想要其他函数。也许这个例子不是最合适的,但我感觉这种情况可能会泛化,如果你的班级是一个很多孩子的班级,可能会很危险。当前的Haskell继承听起来像是隐式地做出了关于父级的默认选择。

相反,如果您的设计没有层次结构,我觉得您必须明确地说明所需的所有属性,这可能意味着风险更小,更清晰,更对称。到目前为止,我所看到的是,这种设计的代价是:在实例定义中编写更多的约束,以及新类型包装器,用于从一组概念到另一组概念的每一个有意义的转换。我不确定,但也许这是可以接受的。不幸的是,我认为Haskell newtypes的自动派生机制不太好用,我希望该语言在newtype包装/展开方面更聪明,并且要求更少的冗长。我不确定,但现在我想起来了,也许newtype包装器的另一种选择是对包含实例的特定变体的模块进行特定导入。

我在写这篇文章时考虑的另一种选择是,也许可以削弱类(px)=>cx的含义,在这里,C的实例不需要选择P的实例,我们可以将其理解为松散地表示,例如,C类也包含P的方法,但没有自动选择P的实例,也不存在与P的其他关系。所以我们可以保留某种更弱的层次结构,这样可能会更灵活。

如果你对这个话题有一些澄清,和/或纠正我可能的误解,谢谢。

共有1个答案

司空奕
2023-03-14

也许你听腻了我的消息,但现在...

我认为超类是作为类型类的一个相对次要和不重要的特性引入的。在Wadler and Blott,1988中,第6节简要讨论了它们,其中给出了示例类Eq a=>Num a。在这里,提供的唯一理由是,在函数类型中编写(Eq a,Num a)=>...是令人讨厌的,而可以加、乘和反的数据类型也应该是可测试的。超类关系允许“一个方便的缩写”。

(这个示例非常糟糕,这一事实突出了这个特性的重要性。现代Haskell没有类Eq a=>Num a,因为所有Num也是Eq的逻辑证明非常弱。示例类Eq a=>Ord a会更有说服力。)

leq :: (Ord a) => a -> a -> Bool
leq x y = x < y || x == y

不打字检查。

关于超类强制特定层次结构的观点,您没有达到目标。

这种“强制”实际上是类型类的一个基本特征。类型类是“由设计决定的”,在给定的Haskell程序中(其中“程序”包括程序使用的所有库,包括base),对于特定类型,只能有特定类型类的一个实例。这种性质被称为相干性。(尽管有一个语言扩展incohorentinstances,但它被认为是非常危险的,只有当特定类型的特定类型类的所有可能实例在功能上等效时才应该使用。)

class Functor a => Monad a

注意,这与monad类型是否只有一个合理的functor实例的问题是分开的。原则上,我们可以使用不兼容的functormonad实例定义违反法律的数据类型。无论functor是否是monad的超类,我们仍然只能在整个程序中使用一个函数mytype实例和一个monad函数mytype实例。

 类似资料:
  • 当使用“joined”、“single”或“concrete”表继承样式在继承层次结构中映射类时,如中所述 映射类继承层次结构 通常的行为是,对特定基类的查询也将生成与子类相对应的对象。当单个查询能够返回每个结果行具有不同类或子类的结果时,我们使用术语“多态加载”。 在多态加载领域,特别是联合表继承和单表继承,还有一个额外的问题,子类属性需要预先查询,然后再加载。当预先查询某个特定子类的属性时,我

  • SQLAlchemy支持三种继承形式: 单表继承 ,其中几种类型的类由一个表表示, 具体的表继承 ,其中每种类型的类都由独立的表表示,并且 联接表继承 ,其中类层次结构在依赖表中被分解,每个类都由其自己的表表示,该表只包含该类的本地属性。 最常见的继承形式是单表和联接表,而具体的继承则面临更多的配置挑战。 在继承关系中配置映射器时,SQLAlchemy可以加载元素 polymorphically

  • 问题内容: 我有两个平行的继承链: 我的经验是,并行继承层次结构在增长时会成为维护上的麻烦。 即不添加方法到我的主要类。 如何避免并行继承层次结构而又不破坏关注点分离的概念? 问题答案: 我正在考虑使用“访客”模式。 这样,您就可以避免多余的继承树,并使格式化逻辑与Vehicle类分开。当然,当您创建新的载具时,您必须向Formatter接口添加另一种方法(并在Formatter接口的所有实现中实

  • 我想不出为继承层次结构创建视图方法。如果我像下面的代码一样创建类层次结构,那么我就不能从bview.set(...)中正确使用B类的方法和属性而不进行强制转换,因为BView是从AView继承的。和Set method signature接受A类型的变量,但在BView中我希望设置B类型的变量。我该如何解决我的问题? 谢谢你。:3

  • 问题内容: 我在 .NET for WinRT(C#)中 ,我想将JSON字符串反序列化为,然后将字典值稍后转换为实际类型。JSON字符串可以包含对象层次结构,我也希望在其中包含子对象。 这是应该能够处理的示例JSON: 我尝试使用 DataContractJsonSerializer 这样做: 实际上,这对于第一个级别是可行的,但是 “父母” 只是一个不能强制转换为的对象: 然后,我尝试使用 J