简体   繁体   English

Haskell继承类型类

[英]Haskell inheriting type classes

Suppose I have the following class: 假设我有以下课程:

class P a where
  nameOf :: a -> String

I would like to declare that all instances of this class are automatically instances of Show . 我想声明此类的所有实例都是Show实例。 My first attempt would be the following: 我的第一次尝试是:

instance P a => Show a where
  show = nameOf

My first attempt to go this way yesterday resulted in a rabbit warren of language extensions: I was first told to switch on flexible instances, then undecidable instances, then overlapping instances, and finally getting an error about overlapping instance declarations. 昨天我第一次尝试使用这种方式导致了语言扩展的混乱:首先被告知要打开灵活的实例,然后打开不确定的实例,然后再打开实例,最后遇到关于重复实例声明的错误。 I gave up and returned to repeating the code. 我放弃并返回重复代码。 However, this fundamentally seems like a very simple demand, and one that should be easily satisfied. 但是,从根本上讲,这似乎是一个非常简单的需求,应该容易满足。

So, two questions: 因此,有两个问题:

  1. Is there a trivially easy way to do this that I've just missed? 有没有一种我刚才错过的简单方法?
  2. Why do I get an overlapping instances problem? 为什么会出现重叠实例问题? I can see why I might need UndecidableInstances , since I seem to be violating the Paterson condition, but there are no overlapping instances around here: there are no instances of P , even. 我可以看到为什么我可能需要UndecidableInstances ,因为我似乎违反了Paterson条件,但是这里没有重叠的实例:甚至没有P实例。 Why does the typechecker believe there are multiple instances for Show Double (as seems to be the case in this toy example)? 为什么类型检查器认为Show Double有多个实例(在这个玩具示例中似乎就是这种情况)?

You get the overlapping instances error because some of your instances of P may have other instances of Show and then the compiler won't be able to decide which ones to use. 之所以会出现重叠实例错误,是因为您的P某些实例可能具有Show其他实例,然后编译器将无法决定使用哪个实例。 If you have an instance of P for Double , then there you go, you get two instances of Show for Double : yours general one and the one already declared in Haskell's base library. 如果您有一个DoubleP实例,那么您将获得Show for Double两个实例:您的常规实例和已经在Haskell基库中声明的实例。 How this error is triggered is correctly stated by @augustss in the comments to your question. @augustss在您的问题注释中正确说明了如何触发此错误。 For more info see the specs . 有关更多信息,请参见规格

As you already know, there is no way to achieve what you're trying without the UndecidableInstances . 如您所知,没有UndecidableInstances ,就无法实现您正在尝试的东西。 When you enable that flag you must understand that you're taking over the compiler's responsibility to ensure that there won't arise any conflicting instances. 启用该标志时,您必须了解您正在承担编译器的责任,以确保不会出现任何冲突的实例。 This means that, of course, there mustn't be any other instances of Show produced in your library. 这意味着,当然,您的库中不得存在其他任何Show实例。 This also means that your library won't export the P class, which will erase the possibility of users of the library declaring the conflicting instances. 这也意味着您的库不会导出P类,这将消除库用户声明冲突实例的可能性。

If your case somehow conflicts with the said above, it's a reliable sign of that there must be something wrong with it. 如果您的情况与上述内容有冲突,则可以肯定地表明问题一定存在。 And in fact there is... 实际上有...


What you're trying to achieve is incorrect above all. 首先,您要实现的目标是错误的。 You are missing several important points about the Show typeclass, distinguishing it from constructs like a toString method of popular OO languages: 您缺少有关Show类型类的几点要点,将其与流行的OO语言的toString方法之类的构造区分开来:

  1. From Show's haddock : 秀的黑线码头

    The result of show is a syntactically correct Haskell expression containing only constants, given the fixity declarations in force at the point where the type is declared. show的结果是在语法上正确的Haskell表达式,其中仅包含常量,并且在声明类型的那一刻使用了固定性声明。 It contains only the constructor names defined in the data type, parentheses, and spaces. 它仅包含在数据类型,括号和空格中定义的构造函数名称。 When labelled constructor fields are used, braces, commas, field names, and equal signs are also used. 当使用带标签的构造函数字段时,还使用大括号,逗号,字段名称和等号。

    In other words, declaring an instance of Show , which does not produce a valid Haskell expression, is incorrect per se. 换句话说,声明Show实例并不会产生有效的Haskell表达式本身是错误的。

  2. Given the above it just doesn't make sense to declare a custom instance of Show when the type allows to simply derive it. 鉴于上述情况,当类型允许简单地派生Show时,声明Show的自定义实例就没有意义。

  3. When a type does not allow to derive it (eg, GADT), generally you'll still have to stick to type-specific instances to produce correct results. 当某个类型不允许派生它时(例如GADT),通常您仍然必须坚持使用特定于类型的实例来产生正确的结果。

So, if you need a custom representation function, you shouldn't use Show for that. 因此,如果您需要自定义表示功能,则不应为此使用Show Just declare a custom class, eg: 只需声明一个自定义类,例如:

class Repr a where
  repr :: a -> String

and approach the instances declaration responsibly. 并负责任地处理实例声明。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM