我会建议镜头和默认实例的组合。如果您还没有导入Control.Lens
一半的模块,现在是时候开始了!镜头到底是什么东西?镜头是一个 getter 和一个 setter 组合成一个函数。而且它们非常可组合。每当您需要访问或修改数据结构的某些部分但您认为记录语法笨拙时,镜头就在那里。
所以,你需要做的第一件事——启用 TH 和 import Control.Lens
。
{-# LANGUAGE TemplateHaskell #-}
import Control.Lens
您需要对数据类型进行的修改是为所有字段添加名称,如下所示:
data SpecialDslExpression = MyExpression { _exprType :: String
, _exprParams :: [Int]
, _exprCost :: Double
, _exprComment :: [String]
, _exprLog :: Maybe Bool
} deriving Show
字段名称开头的下划线对于下一步很重要。因为现在我们要为场生成镜头。我们可以要求 GHC 使用 Template Haskell 为我们做这件事。
$(makeLenses ''SpecialDslExpression)
然后需要做的最后一件事是构造一个“空”实例。请注意,没有人会静态检查您是否确实填写了所有必填字段,因此您最好在error
这些字段中添加一个,这样您至少会遇到运行时错误。像这样的东西:
emptyExpression = MyExpression (error "Type field is required!") [] 0.0 [] Nothing
现在你准备好了!您不能使用emptyExpression
,它会在运行时失败:
> emptyExpression
MyExpression {_exprType = "*** Exception: Type field is required!
但!只要您填充类型字段,您将是金色的:
> emptyExpression & exprType .~ "Test expression"
MyExpression { _exprType = "Test expression"
, _exprParams = []
, _exprCost = 0.0
, _exprComment = []
, _exprLog = Nothing
}
如果需要,您也可以一次填写多个字段。
> emptyExpression & exprType .~ "Test expression"
| & exprLog .~ Just False
| & exprComment .~ ["Test comment"]
MyExpression { _exprType = "Test expression"
, _exprParams = []
, _exprCost = 0.0
, _exprComment = ["Test comment"]
, _exprLog = Just False
}
您还可以使用镜头将功能应用于字段,或查看字段的字段内部,或修改任何其他现有表达式等。我绝对建议看看你能做什么!