You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 06:36:10