使用Monad解析JSON文档以查找特定值?

时间:2017-10-08 15:26:11

标签: haskell monads

我是Haskell的初学者,我正在尝试使用https://hackage.haskell.org/package/json-0.9.1/docs/Text-JSON.html来解析JSON文档。

在我的任务中,我获得了一个JSON文档,我想返回对应于“index”的值,例如在以下情况中:

{
    "root": [
        {
            "root1": 157538
        },
        {
            "root2": [
                {
                    "leaf21": 3
                }
            ]
        },
        {
            "root3": [
                {
                    "leaf31": "somestring"
                },
                {
                    "index": "foundit"
                }
            ]
        }
    ]
}

具体来说:如果出现JSON文档和“root”之类的路径 - > “root3” - > “索引”存在,我想返回“foundit”,否则我想返回Nothing。文档中的其他内容都是任意的:root3,root2,root1,root可能存在也可能不存在等。

现在我可以使用大量的case语句和模式匹配来做到这一点,但是阅读了https://wiki.haskell.org/All_About_Monads,我想知道是否有更好的方法使用类似于Maybe Monad和羊克隆示例的东西,但是我不知道如何编写绑定函数...

[在我的实际案例中,我寻求的价值实际上是文件的19深,所以我有很多案例陈述]

请问你能建议如何使用Monads吗?

1 个答案:

答案 0 :(得分:3)

是的,那些case语句不是必需的

你的猜测是正确的 - 但在这种情况下monad不是正确的答案(没有双关语意图 1 )。

这对TraversalsPrismsLenses来说非常棒 - 当然还有伟大的aeson - 库和lens-aeson

{-# LANGUAGE OverloadedStrings #-}
module Test where

import Control.Lens
import Data.Aeson
import Data.Aeson.Lens
import Data.Monoid ((<>))

jsonString = "{\"root\":[{\"root1\":157538}"
           <>          ",{\"root2\":[{\"leaf21\":3}]}"
           <>          ",{\"root3\":[{\"leaf31\":\"somestring\"}"
           <>                      ",{\"index\":\"foundit\"}]}]}"

val :: Maybe Value
val = decode jsonString

indexMaybe :: Maybe Value
indexMaybe = val ^? _Just . key "root"  . values
                          . key "root3" . values
                          . key "index"

那么这是做什么的?

  • decodeByteString转换为Maybe Value - Maybe,因为解析可能会失败!

  • 然后(^?)运算符预览遍历 - 即它通过JSON对象并遵循您给出的json路径;

为此,您至少要知道“索引”的路径,如果此路径未知,您必须对镜头/棱镜/遍历进行更多研究,或者对解析后的对象进行简单的树搜索

对于那些没时间在json对象中实现搜索“index”的人来说,这是一个扰流器:

  

search :: Text -> Value -> Maybe Value
search txt o@(Object o') = let f y@(Just x) _ = y
                               f _ v = search txt v
                            in case o ^? key txt of
                                 Nothing -> foldl' f Nothing o'
                                 x -> x
search txt a@(Array a') = let f y@(Just x) _ = y
                              f _ v = search txt v
                           in foldl' f Nothing a'
search _ _ = Nothing

替代

正如@MarkSeeman已经提到的 - 一个简单的文本搜索,可能会更有效率。

1 :好吧可能有点