我理解您为什么要这样做,但是不幸的是,Haskell类似乎以您所说的方式“开放”只是一种幻想。许多人认为,执行此操作的可能性是Haskell规范中的错误,出于以下原因,我将对此进行解释。无论如何,如果确实不适合该实例,则需要在声明该类的模块或声明该类型的模块中声明它,这可能表明您应该使用anewtype
或其他包装器围绕您的类型。
需要避免孤立实例的原因远远超出了编译器的便利性。从其他答案中可以看出,该主题颇具争议。为了平衡讨论,我将解释一种观点,即永远不要写孤立的实例,我认为这是经验丰富的Haskellers中的多数意见。我的观点在中间,我将在最后解释。
问题源于以下事实:当同一类和类型存在多个实例声明时,标准Haskell中没有机制来指定要使用的实例。而是,程序被编译器拒绝。
最简单的效果是,您可以拥有一个运行良好的程序,由于其他人对您的模块的依赖性很大,因此该程序会突然停止编译。
更糟糕的是,由于远距离的更改,正在运行的程序可能会在运行时开始崩溃。您可能使用的是假设来自某个实例声明的方法,并且可以用另一个实例替代它,而该实例恰好足以导致您的程序莫名其妙地崩溃,因此它可能会被无声地替换。
想要保证这些问题永远不会发生的人必须遵循以下规则:如果任何人在任何地方都已经为某种类型声明了某个类的实例,则在编写的任何程序中都不得再次声明其他实例任何人。当然,有一种使用anewtype
声明新实例的解决方法,但这始终至少是一个小麻烦,有时是一个大麻烦。因此,从这个意义上讲,那些故意编写孤立实例的人是相当不礼貌的。
那么该问题该怎么办呢?反孤儿实例阵营说,GHC警告是一个错误,它必须是一个错误,它拒绝任何声明孤儿实例的尝试。同时,我们必须自律,不惜一切代价避免这样做。
如您所见,有些人并不那么担心那些潜在的问题。正如您所建议的那样,他们实际上鼓励使用孤立实例作为关注点分离的工具,并说应该仅在逐案的基础上确保没有问题。别人的孤儿给我带来了很多不便,使我确信这种态度过于武断。
我认为正确的解决方案是在Haskell的导入机制中添加扩展,以控制实例的导入。那不能完全解决问题,但是可以为保护我们的程序免受世界上已经存在的孤立实例的损害提供一些帮助。然后,随着时间的流逝,我可能会深信,在某些有限的情况下,一个孤立的实例也许不会那么糟糕。(正是这种诱惑,才使反孤儿阵营中的一些人反对我的提议。)
从所有这一切得出的结论是,至少暂时而言,我强烈建议您避免声明任何孤立实例,如果没有其他原因,则应考虑其他实例。使用newtype
。