为记录类型定义Monoid实例的简洁实现方法问询
更简洁的Options Monoid实例实现方法
当然有更简洁的方式来实现这个Monoid实例,不用手动写所有的Nothing!这里有几种实用的方案,根据你的需求选择:
1. 利用Generic自动派生Monoid(最省心)
如果你启用一些Haskell语言扩展,可以让编译器自动帮你生成符合要求的Monoid实例,包括全Nothing的mempty。
首先在文件顶部启用必要的扩展:
{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DeriveAnyClass #-}
然后修改你的类型定义,派生Generic和Monoid:
data Options = Options { _optionOne :: Maybe Integer , _optionTwo :: Maybe Integer , _optionThree :: Maybe String -- 更多字段随便加,不用改实例代码! } deriving (Show, Generic, Monoid)
这样编译器会自动生成:
mempty:所有字段都是Nothing的Options(因为Maybe的Monoid实例中mempty = Nothing)mappend:对每个字段分别应用Maybe的mappend逻辑(即保留第一个Just值,或者当两个都是Just时合并内部的Semigroup值)
2. 借助Applicative的pure(手动控制但简洁)
如果你不想依赖Generic,可以利用记录类型的Applicative实例来生成mempty。首先启用DeriveApplicative扩展:
{-# LANGUAGE DeriveApplicative #-}
然后定义Monoid实例:
data Options = Options { _optionOne :: Maybe Integer , _optionTwo :: Maybe Integer , _optionThree :: Maybe String } deriving (Show, Applicative) instance Monoid Options where mempty = pure Nothing -- 一行搞定全Nothing的mempty mappend a b = liftA2 mappend a b -- 自动对每个字段做mappend
pure x对于记录类型来说,会把所有字段都设置为x,所以pure Nothing正好是你要的全空Options。
3. 使用Default类(适合更通用的默认值场景)
如果你用data-default库,还可以借助Default类来实现:
首先安装库(如果没装的话),然后启用扩展:
{-# LANGUAGE DeriveDefault #-}
然后派生Default,并在Monoid实例中用def:
import Data.Default (Default(..)) data Options = Options { _optionOne :: Maybe Integer , _optionTwo :: Maybe Integer , _optionThree :: Maybe String } deriving (Show, Default) instance Monoid Options where mempty = def -- def会生成所有字段为默认值的实例,Maybe的默认值就是Nothing mappend a b = liftA2 mappend a b
这种方式不仅能用于Monoid的mempty,还能在其他场景复用这个默认实例,非常灵活。
内容的提问来源于stack exchange,提问作者user4601931
相关产品推荐
相关产品推荐

