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

使用Aeson处理JSON:abcs字段值转绝对路径的类型问题

解决Haskell中JSON字段的绝对路径更新问题

针对你遇到的JSON中abcs字段值转绝对路径的类型问题,我来帮你梳理错误原因并给出解决方案:

问题回顾

你需要读取JSON文件,将动态键对应的abcs值更新为绝对路径,期望updatePaths返回IO Object类型,但一直被类型转换问题困扰。

示例JSON

{ "abcs": { "{crtl}": "crtl.abc", "{wt}": "wt.abc" } }

原代码及编译错误

你的原代码尝试用Hm.map处理Object,但存在两个核心类型问题:

  1. absolute_path返回IO String,但你试图直接将它作为Value存入HashMap,导致IO String和Value类型不匹配
  2. Object是HashMap Text Value,而createFullPath期望参数是[Char],无法直接从Value转换

原代码:

{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}

module TCT.ScenarioRunner where

import Network.HTTP.Simple
import Data.Aeson
import GHC.Generics
import qualified Data.ByteString.Lazy as B
import qualified Data.HashMap.Strict as Hm
import Data.Text.Internal
import Filesystem.Path
import System.Path.NameManip (absolute_path)

loadFile :: IO B.ByteString
loadFile = B.readFile "resources/initialise_body.json"

initialise :: String -> IO ()
initialise sessionId = do
  raw <- loadFile
  let json = (eitherDecode raw) :: Either String Value
  case json of
    Left err -> putStrLn err
    Right (Object ps) -> case Hm.lookup "abcs" ps of
      Nothing -> putStrLn "Could not find abcs"
      Just (Object abcs) -> do
        (putStrLn "Found abcs")
        result <- print $ updatePaths abcs
        putStrLn "Bla"
        putStrLn "TBD: initialise"

updatePaths :: Object -> Object
updatePaths obj = Hm.map createFullPath obj
  where createFullPath val = absolute_path ("resources/abcs/" ++ val)

编译错误:

src/TCT/ScenarioRunner.hs:71:22-46: error: …
• Couldn't match type ‘IO String’ with ‘Value’
  Expected type: Object
  Actual type: Hm.HashMap Text (IO String)
• In the expression: Hm.map createFullPath obj
  In an equation for ‘updatePaths’:
      updatePaths obj = Hm.map createFullPath obj
      where createFullPath val = absolute_path ("resources/abcs/" ++ val)
|
src/TCT/ScenarioRunner.hs:71:44-46: error: …
• Couldn't match type ‘Value’ with ‘[Char]’
  Expected type: Hm.HashMap Text [Char]
  Actual type: Object
• In the second argument of ‘Hm.map’, namely ‘obj’
  In the expression: Hm.map createFullPath obj
  In an equation for ‘updatePaths’:
      updatePaths obj = Hm.map createFullPath obj
      where createFullPath val = absolute_path ("resources/abcs/" ++ val)
|
Compilation failed.

正确解决方案

我们需要用traverse来处理带IO的HashMap映射,同时正确处理Value和Text/String的转换。修改后的updatePaths如下:

updatePaths :: Object -> IO Object
updatePaths (obj :: Object) = traverse createFullPath obj
  where
    createFullPath :: Value -> IO Value
    createFullPath (String val) = (String . T.pack) <$> absolute_path ("resources/abcs/" ++ (T.unpack val))
    createFullPath x = pure x -- 忽略非字符串类型的值

为什么这样可行?

我们来拆解traverse的类型签名:

… => (a -> f b) -> t a -> f (t b)

结合我们的场景:

  • a是Value:因为Object本质是HashMap Text Value,每个元素都是Value
  • f是IO:因为absolute_path是IO操作,我们需要将IO上下文保留到最终的IO Object中
  • t是HashMap Text:对应Object的容器类型

代入后得到的具体类型就是:

(Value -> IO Value) -> HashMap Text Value -> IO (HashMap Text Value)

这完全匹配我们期望的IO Object类型,既解决了IO操作的上下文问题,也正确处理了Value和字符串类型的转换。

内容的提问来源于stack exchange,提问作者Casper Thule Hansen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 09:50:33