如何覆盖派生的 Eq 实例?

How to override the derived Eq instance?

我想知道为什么 email-validate 包在以下代码中导出 Eq:

data EmailAddress = EmailAddress ByteString ByteString
   deriving (Eq, Ord, Data, Typeable, Generic) 

我的意思是,我一直在使用 Text 作为电子邮件地址,直到我意识到我需要让它们不区分大小写(所以我没有将 Example@ex.ampleexample@ex.ample 保存为 2不同的地址),所以我到了这个图书馆才发现它派生了 Eq.

那么,派生Eq而不是自制不区分大小写的实例是否合理?。 另外,如果我要使用这个库,我怎么能为 EmailAdress 提供我自己的 Eq 实例?

So, is it reasonable to derive Eq instead of a self-made case-insensitive instance?

这取决于你想要什么。我确定包的作者对 Eq 实例有他们的理由。

Also, if i were to use this library, how could i provide my own Eq instance for EmailAdress?

你不能"override"他们的实例。此类问题的通常解决方案是 newtype 包装器,您可以在其上编写自己的实例:

newtype MyEmailAddress = MyEmailAddress EmailAddress

然后您可以自由定义您自己的平等版本,可能是:

import Data.Char (toLower)
import qualified Data.ByteString.Char8 as DBC (map)

instance Eq MyEmailAddress where
  MyEmailAddress (EmailAddress a1 d1) == MyEmailAddress (EmailAddress a2 d2) 
    = DBC.map toLower a1 == DBC.map toLower a2 && DBC.map toLower d1 == DBC.map toLower d2

虽然我在做,但请允许我提一下,您甚至可以定义一个模式同义词,使一切变得更好:

{-# LANGUAGE PatternSynonyms #-}
pattern Email address domain = MyEmailAddress (EmailAddress address domain)

然后,您可以轻松地使用 Email "yourName" "yourDomain" 制作一封电子邮件,并对其进行模式匹配。 Eq 实例看起来好多了:

instance Eq MyEmailAddress where
  Email a1 d1 == Email a2 d2 
    = DBC.map toLower a1 == DBC.map toLower a2 && DBC.map toLower d1 == DBC.map toLower d2