Semigroup成为Monoid超类后的兼容代码实现咨询
关于Semigroup/Monoid兼容实现的解答
你的这个实现思路完全符合GHC版本兼容的要求,而且完美满足了你不想依赖semigroups包、也不想把mappend放到顶层的需求,具体来说:
- 版本隔离的正确性:你通过
#if MIN_VERSION_base(4,9,0)条件编译指令,精准隔离了base 4.9及以上版本的Semigroup相关代码——这正是GHC将Semigroup纳入标准库并作为Monoid超类的版本节点,旧版本(base <4.9)会自动忽略这部分代码,完全不会影响编译。 - 类型类契约的一致性:在base 4.9+中,Monoid默认继承自Semigroup,且Semigroup的
<>方法默认就是mappend,所以你只需要定义好Monoid的mempty和mappend,Semigroup实例就能自动继承正确的行为,不需要额外实现<>,这部分你的写法完全没问题。
不过有个细节需要注意:要确保你的mappend实现严格遵守Semigroup的结合律(即a <> (b <> c) = (a <> b) <> c),因为Semigroup实例会直接复用mappend的逻辑,违反结合律会破坏类型类的语义契约,导致潜在的bug。
如果想要让代码更简洁一点,你也可以把Semigroup实例的写法简化成:
#if MIN_VERSION_base(4,9,0) import Data.Semigroup () instance Semigroup Foo where (<>) = mappend #endif
不过这只是风格问题,你原来的写法已经完全满足兼容要求了。
内容的提问来源于stack exchange,提问作者Bergi
相关产品推荐
相关产品推荐

