当a存在Monoid实例时能否为Identity a定义Alternative实例
核心前提
Alternative 类型类的契约要求,其实现的 empty :: f a 和 <|> :: f a -> f a -> f a 必须对任意类型的 a都生效,不能限制 a 的类约束。你想要的实现仅在 a 具备 Monoid 实例时可用,本身不符合标准 Alternative 的定义,这就是你无法直接在实例声明上加 Monoid a 约束的原因(该约束引用的类型变量 a 没有出现在实例头 Alternative Identity 中,标准 Haskell 不允许这种写法)。
可行的解决方案
方案1:自定义专用 newtype(最稳妥,无扩展依赖)
定义专属的包装类型,仅针对内部有 Monoid 实例的场景提供 Alternative 实例,符合标准 Haskell 规范:
newtype MonoidalIdentity a = MonoidalIdentity a deriving newtype (Functor, Applicative, Show, Eq) -- 按需派生其他实例 instance Monoid a => Alternative MonoidalIdentity where empty = MonoidalIdentity mempty MonoidalIdentity a <|> MonoidalIdentity a' = MonoidalIdentity (a <> a')
方案2:使用 GHC 扩展突破标准限制(不推荐生产环境使用)
如果一定要给原生 Identity 添加该实例,需要开启三个 GHC 扩展:FlexibleInstances、UndecidableInstances、QuantifiedConstraints,写法如下:
{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE QuantifiedConstraints #-} instance (forall a. Monoid a) => Alternative Identity where empty = Identity mempty Identity a <|> Identity a' = Identity (a <> a')
注意:该写法要求所有用到
Identity的 Alternative 实例的场景下,内部类型必须满足 Monoid 约束,否则会触发编译报错,且违反了 Alternative 的标准契约,可能导致依赖标准 Alternative 行为的库出现不可预期的问题。
内容的提问来源于stack exchange,提问作者l7r7
相关产品推荐
相关产品推荐

