【问题标题】:How to extract data using Text.JSON?如何使用 Text.JSON 提取数据?
【发布时间】:2026-01-16 07:30:01
【问题描述】:

我正在尝试围绕ffprobe 编写一个包装器,以{"format": {"format_name": value}} 格式提取value。 JSON由创建的进程输出。这就是我得到的结果。

import System.Process
import System.Environment
import System.IO
import Text.JSON

main = do
    args <- getArgs
    (_, Just out, _, p) <- createProcess
        (proc "ffprobe" [args!!0, "-of", "json", "-show_format"])
        { std_out = CreatePipe }
    s <- hGetContents out
    --putStrLn $ show (decode s :: Result JSValue)
    --waitForProcess p
    --putStrLn $ valFromObj "format_name" format
    --    where format = valFromObj "format" rootObj
    --          (Ok rootObj) = decode s :: Result (JSObject (JSValue))
    let (Ok rootObj) = decode s :: Result (JSObject (JSValue))
    let (Ok format) = valFromObj "format" rootObj :: Result (JSObject (JSValue))
    putStrLn format_name
        where (Ok format_name) = valFromObj "format_name" format

编译失败:

[1 of 1] Compiling Main             ( ffprobe.hs, ffprobe.o )

ffprobe.hs:20:59: error:
    Variable not in scope: format :: JSObject JSValue

我对几件事感到困惑,包括为什么我无法编译最后一行:

  1. 为什么我不能在Result 后面的Ok 中断言::。喜欢:: Result Ok JSObject JSValue

  2. 为什么我不能提取 where 子句中的值?

  3. 为什么是Result (JSObject (JSValue)) 而不是Result JSObject JSValue

  4. 为什么format 超出范围?

我有一种感觉,我正在将 IO 和 Result monad 混合在同一个 do 块或其他东西中。 Result 甚至是单子吗?我可以在一个单独的do 中提取我想要的值,而不会在IO do 中到处乱写吗?

【问题讨论】:

  • 如果您只是想解码 JSON,您知道有一个流行的 Haskell 库,称为 aeson

标签: json haskell io


【解决方案1】:

我认为你的编译错误是因为where 的位置。试试

main = do
    ...
    let (Ok format) = valFromObj "format" rootObj :: Result (JSObject (JSValue))
    let (Ok format_name) = valFromObj "format_name" format
    putStrLn format_name

where 的范围在do 之外,因此它不知道format

【讨论】:

    【解决方案2】:

    你不能这样做:

    main = do
      let bar = "only visible inside main? "
      return baz
      where
        baz = bar ++ " yes, this will break!"
    

    这给出了:

    test.hs:7:11:
        Not in scope: ‘bar’
        Perhaps you meant ‘baz’ (line 7)
    

    与函数参数不同的 Let 绑定在 where 绑定中不可用。以上bar 不在baz 使用范围内。与您的代码进行比较。

    【讨论】: