如何在Haskell的Eq实例中优雅实现Any与所有值相等的逻辑?
解决Haskell自定义Eq实例的冗余代码问题
嘿,这个场景我太熟悉了——自定义Eq实例时,既要处理Any和所有构造器相等的特殊逻辑,又不想重复写一堆A == A = True这种 boilerplate 代码,确实挺烦人的。不用依赖show(毕竟它是给人看的字符串表示,用来判断相等总有点不靠谱),这里有几个更简洁且语义准确的方案:
方案1:借助Enum派生(最简单,无额外依赖)
如果你的MyType构造器都是无参数的(就像你给出的例子),可以给它派生Enum,然后利用fromEnum来快速判断非Any构造器的相等性:
data MyType = Any | A | B | C deriving Enum -- 加上Enum派生 instance Eq MyType where Any == _ = True _ == Any = True x == y = fromEnum x == fromEnum y -- 用枚举值判断相等
fromEnum会给每个构造器分配一个唯一的整数(按定义顺序),相同构造器的枚举值肯定相同,不同的则不同,完美替代了重复的模式匹配。
方案2:用Generic派生(更通用,适合复杂类型)
如果以后你的MyType可能会加带参数的构造器,或者想更通用地处理这类问题,可以用GHC的Generic特性,借助默认的相等实现来减少冗余:
首先要开启DeriveGeneric扩展,然后:
{-# LANGUAGE DeriveGeneric #-} import GHC.Generics data MyType = Any | A | B | C deriving Generic -- 派生Generic instance Eq MyType where Any == _ = True _ == Any = True x == y = eq x y -- 调用Generic提供的默认相等逻辑
这里的eq函数来自GHC.Generics模块,它会自动帮你处理所有非Any构造器的相等判断,完全不用手动写每个构造器的匹配。
为什么不推荐用show?
你提到的x == y = show x == show y虽然能工作,但有个隐患:如果以后你给MyType自定义了Show实例(比如改变输出格式),这个相等判断就会出错,因为它依赖的是字符串表示而非构造器本身的语义。上面的两个方案都是直接基于构造器的身份判断,更符合你想要的相等语义。
内容的提问来源于stack exchange,提问作者Dunno
相关产品推荐
相关产品推荐

