[英]Haskell inheriting type classes
假设我有以下课程:
class P a where
nameOf :: a -> String
我想声明此类的所有实例都是Show
实例。 我的第一次尝试是:
instance P a => Show a where
show = nameOf
昨天我第一次尝试使用这种方式导致了语言扩展的混乱:首先被告知要打开灵活的实例,然后打开不确定的实例,然后再打开实例,最后遇到关于重复实例声明的错误。 我放弃并返回重复代码。 但是,从根本上讲,这似乎是一个非常简单的需求,应该容易满足。
因此,有两个问题:
UndecidableInstances
,因为我似乎违反了Paterson条件,但是这里没有重叠的实例:甚至没有P
实例。 为什么类型检查器认为Show Double
有多个实例(在这个玩具示例中似乎就是这种情况)? 之所以会出现重叠实例错误,是因为您的P
某些实例可能具有Show
其他实例,然后编译器将无法决定使用哪个实例。 如果您有一个Double
的P
实例,那么您将获得Show
for Double
两个实例:您的常规实例和已经在Haskell基库中声明的实例。 @augustss在您的问题注释中正确说明了如何触发此错误。 有关更多信息,请参见规格 。
如您所知,没有UndecidableInstances
,就无法实现您正在尝试的东西。 启用该标志时,您必须了解您正在承担编译器的责任,以确保不会出现任何冲突的实例。 这意味着,当然,您的库中不得存在其他任何Show
实例。 这也意味着您的库不会导出P
类,这将消除库用户声明冲突实例的可能性。
如果您的情况与上述内容有冲突,则可以肯定地表明问题一定存在。 实际上有...
首先,您要实现的目标是错误的。 您缺少有关Show
类型类的几点要点,将其与流行的OO语言的toString
方法之类的构造区分开来:
从秀的黑线码头 :
show的结果是在语法上正确的Haskell表达式,其中仅包含常量,并且在声明类型的那一刻使用了固定性声明。 它仅包含在数据类型,括号和空格中定义的构造函数名称。 当使用带标签的构造函数字段时,还使用大括号,逗号,字段名称和等号。
换句话说,声明Show
实例并不会产生有效的Haskell表达式本身是错误的。
鉴于上述情况,当类型允许简单地派生Show
时,声明Show
的自定义实例就没有意义。
当某个类型不允许派生它时(例如GADT),通常您仍然必须坚持使用特定于类型的实例来产生正确的结果。
因此,如果您需要自定义表示功能,则不应为此使用Show
。 只需声明一个自定义类,例如:
class Repr a where
repr :: a -> String
并负责任地处理实例声明。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.