haskell - 为特定构造函数创建实例类
问题描述
假设我有以下数据:
data A
= B Int
| C Float
| D A
如果我想派生Eq
,但更改输出以便将两个项目与构造函数进行比较D
总是相等的,有没有办法在不为所有其他构造函数实现它的情况下这样做?对于其他情况,我想派生默认Eq
实现。
我想要达到的目标是
instance Eq A where
(D _) == (D _) = True
_ == _ = undefined -- Use default eq
解决方案
没有直接的方法可以将Eq A
GHC 生成的默认实例合并到您自己的Eq A
实例中。问题是实例代码的生成与定义这些实例的过程相关——生成默认Eq A
代码的唯一方法是实际生成唯一的Eq A
实例,一旦生成实例,你就不能真正更改。即使使用与 GHC“派生”相关的扩展,我也看不到任何解决此问题的方法。
但是,您可以使用Eq
包提供的默认实例的重新实现。generic-deriving
有一些序言:
{-# LANGUAGE DeriveGeneric #-}
import GHC.Generics
import Generics.Deriving.Eq -- from package generic-deriving
使用派生Generic
实例定义您的数据类型:
data A
= B Int
| C Float
| D A
deriving (Generic)
然后,GEq
为构造函数定义一个实现您的特殊情况的实例,D
而其余的则遵循默认实现。
instance GEq A where
D _ `geq` D _ = True
x `geq` y = x `geqdefault` y
最后,定义一个Eq
使用这个通用相等类的实例。
instance Eq A where
(==) = geq
之后,它应该按预期工作:
> D (B 10) == D (B 20)
True
> B 10 == B 20
False
>
但是,接受评论中的建议可能更合理,或者:
按照@malloy 的建议去做。您尝试定义的操作不是真的
(==)
,那么为什么需要命名它(==)
?只需派生通常的Eq
实例并编写一个单独的函数来避免不需要的递归:equalClasses :: A -> A -> Bool equalClasses (D _) (D _) = True equalClasses x y = x == y
如果您真的想使用 a
(==)
,我认为使用newtype
@luqui 建议的 a 可能是最惯用的方法:data A' = B Int | C Float | D A' deriving (Eq) newtype A = A A' instance Eq A where A (D _) == A (D _) = True A x == A y = x == y
推荐阅读
- laravel - Laravel:使用另一个表中的变量在循环内求和
- node.js - Jasmine2 + Protractor + Browserstack - 由于超时错误执行会停止并且一致的错误
- php - 如何将 JSON 字符串传递到 MySQL?
- python - 响应模拟 requests.ConnectionError,断言函数
- r - 在R中取消嵌套多个嵌套数据框
- vba - 进一步到“MS Access 报告 - 字符处换行?” 问题;
- python - Python Path - 获取要在 Python 中访问的目录
- xquery - 无法围绕 XQuery 输出包装元素
- selenium - 我们可以在 Selenium 中使用 CssSelectors 实现父子关系吗
- javascript - 如何将偏移量应用于固定元素(底部:0)