Dan*_*yer 82 haskell typeclass ghc
使用该-Wall
选项编译我的Haskell应用程序时,GHC会抱怨孤立的实例,例如:
Publisher.hs:45:9:
Warning: orphan instance: instance ToSElem Result
Run Code Online (Sandbox Code Playgroud)
类型类ToSElem
不是我的,它由HStringTemplate定义.
现在我知道如何解决这个问题(将实例声明移动到声明Result的模块中),我知道为什么GHC更愿意避免孤立的实例,但我仍然相信我的方式更好.我不在乎编译器是否带来不便 - 而不是我.
我想ToSElem
在Publisher模块中声明我的实例的原因是因为它是依赖于HStringTemplate的Publisher模块,而不是其他模块.我试图保持关注点的分离,并避免让每个模块依赖于HStringTemplate.
我认为,与Java的接口相比,Haskell类型类的优点之一是它们是开放的而不是封闭的,因此实例不必在与数据类型相同的位置声明.GHC的建议似乎是忽略了这一点.
所以,我正在寻找的是要么认可我的想法是正确的,要么我有理由忽视/压制这个警告,或者更有说服力的反对我做事的做法.
Yit*_*itz 89
我理解你为什么要这样做,但不幸的是,Haskell课程似乎以你说的方式"开放"可能只是一种错觉.许多人认为这样做的可能性是Haskell规范中的一个错误,原因我将在下面解释.无论如何,如果它实际上不适合于实例,则需要在声明类的模块中声明,或者在声明类型的模块中声明,这可能表示您应该使用一个newtype
或其他包装器围绕你的类型.
需要避免孤立实例的原因远远超过编译器的便利性.从其他答案中可以看出,这个话题颇具争议性.为了平衡讨论,我将解释一个观点,即永远不应该写孤立实例,我认为这是经验丰富的Haskellers中的多数意见.我自己的意见在中间,我将在最后解释.
问题源于这样一个事实:当同一个类和类型存在多个实例声明时,标准Haskell中没有指定要使用的机制.相反,程序被编译器拒绝.
最简单的效果是你可以拥有一个完美的工作程序,它会突然停止编译,因为其他人在模块的某些远程依赖中做出了改变.
更糟糕的是,由于远程更改,工作程序可能会在运行时开始崩溃.您可能正在使用一种假设来自某个实例声明的方法,并且它可以默默地被另一个不同的实例替换,该实例的大小不同会导致程序无法解决.
想要保证这些问题不会发生在他们身上的人必须遵循以下规则:如果任何人,任何地方,曾经为某种类型声明了某个类的实例,那么在任何程序中都不能再声明其他实例.任何人.当然,有一种使用a newtype
来声明一个新实例的解决方法,但这至少是一个小麻烦,有时候是一个很大的不便.所以在这个意义上,那些故意写孤儿实例的人是相当不礼貌的.
那么应该对这个问题做些什么呢?反孤立实例阵营说GHC警告是一个错误,它需要是一个错误,拒绝任何声明孤立实例的企图.与此同时,我们必须自律,不惜一切代价避免它们.
如您所见,有些人并不那么担心这些潜在的问题.他们实际上鼓励使用孤儿实例作为分离问题的工具,正如您所建议的那样,并且应该根据具体情况确保没有问题.我被其他人的孤儿实例给我带来了不便,以确信这种态度太过于无耻.
我认为正确的解决方案是为Haskell的导入机制添加扩展,以控制实例的导入.这不会完全解决问题,但它会为保护我们的计划免受世界上已有的孤儿实例的破坏提供一些帮助.然后,随着时间的推移,我可能会相信,在某些有限的情况下,也许孤儿实例可能并不那么糟糕.(并且这种诱惑是反孤儿阵营中的一些人反对我的提议的原因.)
我从这一切得出的结论是,至少就目前而言,我强烈建议你避免宣布任何孤儿事例,如果没有其他原因,要考虑别人.用一个newtype
.
yai*_*chu 41
来吧,压制这个警告!
你是一个很好的公司.Conal在"TypeCompose"中做到了."chp-mtl"和"chp-transformer"执行此操作,"control-monad-exception-mtl"和"control-monad-exception-monadsfd"执行此操作,等等.
顺便说一句,你可能已经知道了这一点,但对于那些没有这个并且在搜索中绊倒你的问题的人:
{-# OPTIONS_GHC -fno-warn-orphans #-}
Run Code Online (Sandbox Code Playgroud)
编辑:
我承认伊兹在答案中提到的问题是真正的问题.然而,我认为不使用孤立的实例也是一个问题,我试图挑选"最少的所有邪恶",这是非常谨慎地使用孤儿实例.
我在简短的回答中只使用了一个感叹号,因为你的问题表明你已经很清楚这些问题.否则,我会不那么热情:)
有点转移,但我相信在完美的世界中完美的解决方案毫不妥协:
我相信Yitz提到的问题(不知道选择哪个实例)可以在"整体"编程系统中解决,其中:
现在回到幻想世界(或者希望是未来):我建议你在"真正需要"的时候尽量避免使用孤立实例
小智 35
孤儿实例是令人讨厌的,但在我看来,它们有时是必要的.我经常组合库,其中类型来自一个库,而类来自另一个库.当然,不能期望这些库的作者为每种可能的类型和类组合提供实例.所以我必须提供它们,所以他们是孤儿.
当你需要提供一个实例时,你应该将类型包装成一个新类型的想法是一个具有理论价值的想法,但在许多情况下它太繁琐了; 这是那些不以Haskell代码为生的人提出的那种想法.:)
所以继续并提供孤立实例.它们是无害的.
如果您可以使用孤立实例崩溃ghc那么这是一个错误,应该如此报告.(ghc有/没有检测到多个实例的bug并不难解决.)
但请注意,将来某个时候其他人可能会添加您已有的某个实例,并且您可能会收到(编译时)错误.
scl*_*clv 17
在这种情况下,我认为使用孤立实例很好.对我来说一般的经验法则是 - 你可以定义一个实例,如果你"拥有"类型类或者你"拥有"数据类型(或者它的某个组件 - 也就是说,也许一个Maybe MyData的实例也很好,至少有时候).在这些约束中,您决定放置实例是您自己的业务.
还有一个例外 - 如果你既不拥有类型类或数据类型,而是生成二进制而不是库,那么那也没关系.
归档时间: |
|
查看次数: |
7764 次 |
最近记录: |