Haskell(Aeson):如何结合JSON数据与额外值构造记录
嘿,你这个需求其实可以不用先解析出带默认值的记录再手动更新,有不少更简洁的实现方式,我给你几个实用的方案:
方案1:直接解析必要字段后构造完整记录
我们可以跳过给MyRecord定义完整的FromJSON实例,直接从JSON里解析出a和b的值,再结合传入的c值一步构造出完整记录:
import Data.Aeson (decode, withObject, (.:), parseMaybe) import Data.Aeson.Types (Parser) createMyRecord :: String -> String -> Maybe MyRecord createMyRecord json cValue = do obj <- decode json valueA <- parseMaybe (.: "a") obj valueB <- parseMaybe (.: "b") obj return $ MyRecord valueA valueB cValue
如果想把解析逻辑封装得更清晰,也可以写成这样:
createMyRecord :: String -> String -> Maybe MyRecord createMyRecord json cValue = do (aVal, bVal) <- decode json >>= parseParts return $ MyRecord aVal bVal cValue where parseParts = parseMaybe $ withObject "MyRecordParts" $ \o -> do aVal <- o .: "a" bVal <- o .: "b" return (aVal, bVal)
这种方式完全避免了中间生成带默认c值的记录,直接一步到位。
方案2:自定义带外部参数的解析器
如果还是想保留MyRecord的解析逻辑封装,可以写一个接收c值的自定义解析器,把构造逻辑和解析逻辑合并:
import Data.Aeson (decode, withObject, (.:), parseMaybe, Value) import Data.Aeson.Types (Parser) parseMyRecordWithC :: String -> Value -> Parser MyRecord parseMyRecordWithC cValue = withObject "MyRecord" $ \o -> do valueA <- o .: "a" valueB <- o .: "b" return $ MyRecord valueA valueB cValue createMyRecord :: String -> String -> Maybe MyRecord createMyRecord json cValue = do jsonVal <- decode json parseMaybe (parseMyRecordWithC cValue) jsonVal
这个方案的好处是把解析a、b的逻辑集中在一个地方,后续如果字段有变动,只需要修改parseMyRecordWithC即可。
方案3:用Lens简化字段更新(适合已用Lens的项目)
如果你的项目已经引入了lens或者microlens库,可以用Lens的语法让原有的更新逻辑更简洁:
import Data.Aeson (decode) import Control.Lens ((&), (.~)) createMyRecord :: String -> String -> Maybe MyRecord createMyRecord json cValue = (\r -> r & c .~ cValue) <$> decode json
这个本质上还是先解析再更新,但写法更紧凑,适合已经在使用Lens的场景。
总的来说,方案1和方案2是最直接的“一次性构造”方式,完全避免了中间的默认值记录,推荐优先使用。
内容的提问来源于stack exchange,提问作者tomphp
相关产品推荐
相关产品推荐

