假设我定义了一些派生Eq但希望为某些模式插入我自己的(==)定义的数据类型。有没有办法做到这一点,还是我必须为每个模式定义(==)?
e.g。
data Asdf = One Char | Two Char Char --(deriving Eq)
instance Eq Asdf where
(==) (One _) (One _) = True
--otherwise use what the derived definition would have done
--can I do this without defining these patterns myself?
答案 0 :(得分:8)
要做你想做的事情,你必须自己定义,这意味着你必须为每个模式定义它。
基本上data MyType x = A x | B x x deriving (Eq)
将添加等效于
instance Eq x => Eq (MyType x) where
A x1 == A x2 = x1 == x2
B x1 x2 == B x3 x4 = x1 == x3 && x2 == x4
_ == _ = False
请注意,它确定了必要的依赖关系(上面的Eq x =>
部分)以及填充对角线情况 - n 2 2>中的特殊情况使用相同构造函数的可能匹配。
据我所知,它一次性完成这个定义,并且无法深入挖掘现有的实例声明来解决它 - 并且有充分的理由这样做;如果他们让你这样做,那就意味着随着代码库的增长,你无法查看实例派生或deriving (Eq)
子句,并确信你确切知道它的含义,因为代码的其他部分可能猴子补丁,Eq
实例做恶事。
所以一种方法是自己重新定义对角线。但这不是唯一的方式。如果修改多个使用网站比将所有 n 构造函数推送到一个单独的东西中更容易,那么至少有一个替代方案可以工作:
newtype EverythingIsEqual x = E x deriving (Show)
instance Eq (EverythingIsEqual x) where
_ == _ = True
data MyType x = A (EverythingIsEqual x) | B x x deriving (Show, Eq, Ord)
这个newtype
允许您策略性地修改某些术语,以便在没有运行时成本的情况下拥有不同的Eq
关系 - 实际上这几乎是newtypes的两个核心参数之一;除了较小的一个“我希望这两个字符串之间存在类型级差异,但它们只是字符串而且我不想支付任何性能损失”,还有更大的争论“有时我们想告诉Haskell使用不同的Ord
字典而不会弄乱这个字典所依据的任何值,我们只想换掉这些函数。“
答案 1 :(得分:5)
此问题讨论了如何使用https://hackage.haskell.org/package/generic-deriving包对Show
实例执行非常类似的操作:Accessing the "default show" in Haskell?
特别参见这个答案:https://stackoverflow.com/a/35385768/936310
我最近最近将它用于Show
实例,并且效果非常好。您可以类似地为您的类型派生Eq
,假设它足够常规。