Haskell继承类型类

时间:2013-04-04 09:40:25

标签: haskell ghc typeclass

假设我有以下课程:

class P a where
  nameOf :: a -> String

我想声明此类的所有实例都是Show的自动实例。我的第一次尝试将如下:

instance P a => Show a where
  show = nameOf

我昨天第一次尝试这种方式导致了一个语言扩展的兔子:我首先被告知要打开灵活的实例,然后是不可判定的实例,然后重叠实例,最后得到关于重叠实例声明的错误。我放弃了并重新开始重复代码。然而,这从根本上说似乎是一个非常简单的需求,而且应该很容易满足。

所以,有两个问题:

  1. 我错过了一个简单易行的方法吗?
  2. 为什么会出现重叠实例问题?我可以看到为什么我可能需要UndecidableInstances,因为我似乎违反了Paterson条件,但这里没有重叠的实例:没有P的实例,甚至。为什么类型检查器认为Show Double有多个实例(在这个玩具示例中似乎就是这种情况)?

1 个答案:

答案 0 :(得分:5)

您收到重叠实例错误,因为您的某些P实例可能有Show的其他实例,然后编译器将无法决定使用哪些实例。如果你有P Double的实例,那么你可以得到Show Double的两个实例:你的一般实例和已经在Haskell中声明的实例基础库。 @augustss在您的问题的评论中正确说明了如何触发此错误。有关详细信息,请参阅the specs

正如您所知,如果没有UndecidableInstances,就无法实现您的目标。当您启用该标志时,您必须了解您正在接管编译器的责任,以确保不会出现任何冲突的实例。这意味着,当然,您的库中不得出现Show的任何其他实例。这也意味着您的库不会导出P类,这将消除库的用户声明冲突实例的可能性。

如果您的案件与上述情况发生某种冲突,那么这是一个可靠的迹象,表明它一定有问题。事实上还有......


你想要实现的目标是不正确的。您遗漏了关于Show类型类的几个要点,将其与流行的OO语言的toString方法等结构区分开来:

  1. 来自Show's haddock

      

    show的结果是一个语法正确的Haskell表达式,只包含常量,给定在声明类型的位置生效的固定声明。它仅包含数据类型,括号和空格中定义的构造函数名称。使用标记的构造函数字段时,还会使用大括号,逗号,字段名称和等号。

    换句话说,声明Show的实例,它不会产生有效的Haskell表达式,本身就是不正确的。

  2. 鉴于上述内容,当类型允许简单派生时,声明Show的自定义实例是没有意义的。

  3. 当一个类型不允许派生它(例如,GADT)时,通常你仍然必须坚持使用特定类型的实例来产生正确的结果。

  4. 因此,如果您需要自定义表示功能,则不应使用Show。只需声明一个自定义类,例如:

    class Repr a where
      repr :: a -> String
    

    负责任地处理实例声明。