Imp*_*ive 8 haskell typeclass ghc
假设我有以下课程:
class P a where
nameOf :: a -> String
Run Code Online (Sandbox Code Playgroud)
我想声明这个类的所有实例都是自动的实例Show.我的第一次尝试将如下:
instance P a => Show a where
show = nameOf
Run Code Online (Sandbox Code Playgroud)
昨天我第一次尝试这种方式导致了一个语言扩展的兔子:我首先被告知要打开灵活的实例,然后是不可判定的实例,然后重叠实例,最后得到关于重叠实例声明的错误.我放弃了并重新开始重复代码.然而,从根本上说,这似乎是一个非常简单的需求,应该很容易满足.
那么,有两个问题:
UndecidableInstances理解为什么我可能需要,因为我似乎违反了帕特森的条件,但这里没有重叠的实例:P甚至没有实例.为什么typechecker认为有多个实例Show Double(在这个玩具示例中似乎就是这种情况)?您得到重叠实例错误,因为您的某些实例P可能有其他实例,Show然后编译器将无法决定使用哪些实例.如果您有Pfor 的实例Double,那么您可以获得两个Showfor的实例Double:您的一般实例和已经在Haskell基础库中声明的实例.@augustss在您的问题的评论中正确说明了如何触发此错误.有关详细信息,请参阅规格.
正如你已经知道的那样,如果没有这个,你就无法实现你的目标UndecidableInstances.当您启用该标志时,您必须了解您正在接管编译器的责任,以确保不会出现任何冲突的实例.这意味着,当然,Show您的库中不得出现任何其他实例.这也意味着您的库不会导出P类,这将消除库的用户声明冲突实例的可能性.
如果你的案子与上述情况发生某种冲突,那么这是一个可靠的迹象,表明它一定有问题.事实上有......
你想要实现的目标是不正确的.您缺少关于Show类型类的几个重要点,将它与toString流行的OO语言方法之类的结构区分开来:
来自Show的黑线鳕:
show的结果是一个语法正确的Haskell表达式,只包含常量,给定声明类型的点处的强制声明.它仅包含数据类型,括号和空格中定义的构造函数名称.使用标记的构造函数字段时,还使用大括号,逗号,字段名称和等号.
换句话说,声明一个Show不生成有效Haskell表达式的实例本身就是不正确的.
鉴于上述情况,声明Show类型允许简单派生的自定义实例是没有意义的.
当一个类型不允许派生它(例如,GADT)时,通常你仍然必须坚持类型特定的实例来产生正确的结果.
因此,如果您需要自定义表示功能,则不应该使用Show它.只需声明一个自定义类,例如:
class Repr a where
repr :: a -> String
Run Code Online (Sandbox Code Playgroud)
并负责任地处理实例声明.