在以下示例中:
data ColourName
= White
| Grey
| Gray
| Black
| Blue
-- ...
-- hundreds more of colours
-- ...
| LastColor
deriving (Read, Show, Eq)
我想重新定义(==)
,以便Grey
和Gray
评估为相等。
显然,一种方法是不在Eq
中包含deriving
,但是,我必须定义
(==) :: ColourName
(==) White White = True
(==) Gray Gray = True
(==) Grey Grey = True
(==) Gray Grey = True
(==) Grey Gray = True
(==) Black Black = True
-- frickin' log of other colors, hundreds of lines of typing
(==) LastColor LastColor = True
(==) a b = False
这不是我打算做的事。
我也不能
instance Eq ColourName where
(==) :: ColourName -> ColourName -> Bool
(==) Gray Grey = True
(==) Grey Gray = True
(==) a b = (a == b)
因为这会导致无限递归,基本上是未定义的。
有出路吗?
(不,我不想使用data Colour = Colour String
或类似的。我希望将有效颜色表示为枚举,例如提供自动验证,但希望允许最终用户的拼写变化模块!)
答案 0 :(得分:12)
您可以使用派生的Enum
实例:
data ColourName = Gray | Grey | ...
deriving (Read, Show, Enum)
instance Eq ColourName where
Gray == Grey = True
Grey == Gray = True
a == b = fromEnum a == fromEnum b
编辑:您还可以将PatternSynonyms
与GHC 7.8+一起使用。它的工作方式类似于智能构造函数,但也可用于模式匹配。
pattern Gray = Grey
答案 1 :(得分:9)
不要这样做。它在模式匹配方面不会很好用。它会打破像
这样的东西f Gray = g
f x = h
因为模式匹配不关心您的Eq
实例。
休息时,我的意思是它不会有你想要的行为,因为f Grey
最终会调用h
而不是g
,即使你期望{所有f x == f y
{1}}。这意味着程序员必须明确记住为x == y
和f Gray
创建只是愚蠢的案例。
如果你决定有一个丑陋的黑客来允许替代拼写,我想你可以做到
f Grey
启用CPP。
答案 2 :(得分:7)
根据定义,值Grey
和Gray
不相等。没有任何迹象表明它们应该是平等的,除了你附加到它们的额外语义。我会说这是对Eq
类型类的滥用。
定义一个函数来处理这些额外的语义:
sameColour :: Color -> Color -> Bool
sameColour Grey Gray = True
sameColour Gray Grey = True
sameColor a b = a == b
这可以很容易地扩展到处理多种颜色的“同义词”
答案 3 :(得分:6)
与Piezoid的答案类似,使用Show
实例进行比较可能会降低效率:
data ColourName = Gray | Grey | ...
deriving (Show, Read)
instance Eq ColourName where
Gray == Grey = True
Grey == Gray = True
a == b = show a == show b
然后你不必依赖于使用Enum
,但是你必须比较字符串会有一点性能损失。
答案 4 :(得分:4)
我会在这里使用newtype
:
newtype ColourNameEquatingGrayAndGrey = CNEGAG ColourName
instance Eq ColourNameEquatingGrayAndGrey where
CNEGAG Gray == CNEGAG Grey = True
CNEGAG Grey == CNEGAG Gray = True
CNEGAG a == CNEGAG b = a == b
(抱歉愚蠢的类型和构造函数名称......)
这使您可以保留deriving Eq
,这使您非常明确地将代码中的不同拼写放在一起,并且您仍然可以使用nub
等库函数(相比较)必须切换到nubBy sameColour
(如@ cdk' s)或类似的东西)。如果需要,您还可以创建自己的Show
实例,并且运行时成本应该最小。
我现在唯一能想到的缺点是模式匹配变得更加繁琐,但我猜测有100多种替代方案并不是你做的事情!