使用 Monad 解析 JSON 文档以查找特定值?
Parsing a JSON document with a Monad to look for a specific value?
我是 Haskell 的初学者,我正在尝试使用 https://hackage.haskell.org/package/json-0.9.1/docs/Text-JSON.html 来解析 JSON 文档。
在我的任务中,我得到了一个 JSON 文档,我想 return 对应于 "index" 的值,例如在以下情况下:
{
"root": [
{
"root1": 157538
},
{
"root2": [
{
"leaf21": 3
}
]
},
{
"root3": [
{
"leaf31": "somestring"
},
{
"index": "foundit"
}
]
}
]
}
具体来说:如果有一个 JSON 文档和一个像 "root" -> "root3" -> "index" 这样的路径存在,我想 return"foundit",否则我想return没什么。文档中的其他所有内容都是任意的:root3、root2、root1、root 可能存在也可能不存在等。
现在我可以使用大量 case 语句和模式匹配来做到这一点,但在阅读 https://wiki.haskell.org/All_About_Monads 之后,我想知道是否有更好的方法使用类似于 Maybe Monad 和绵羊克隆示例的方法,但是我不确定如何编写绑定函数...
[在我的真实案例中,我寻求的价值实际上在文档中有 19 个深度,所以我有很多案例陈述]
请问您能否建议如何使用 Monad 来做到这一点?
是的,不需要那些 case
语句
您的猜测是正确的 - 但在这种情况下单子不是正确答案(没有双关语意1)。
这对 Traversals
、Prisms
和 Lenses
来说是一项伟大的工作 - 当然还有伟大的 aeson-library and 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"
那么这是做什么的?
decode
将 ByteString
转换为 Maybe Value
- Maybe
因为解析可能会失败!
然后 (^?)
运算符预览遍历 - 即它通过 JSON 对象并遵循您提供的 json 路径;
为此你至少要知道通往 "index" 的路径,如果这条路径未知,你必须对 lenses/prisms/traversals 投入更多的研究或进行简单的树搜索在解析的对象上。
这里有一个剧透,供那些没有时间在 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: 好吧,也许有点
我是 Haskell 的初学者,我正在尝试使用 https://hackage.haskell.org/package/json-0.9.1/docs/Text-JSON.html 来解析 JSON 文档。
在我的任务中,我得到了一个 JSON 文档,我想 return 对应于 "index" 的值,例如在以下情况下:
{
"root": [
{
"root1": 157538
},
{
"root2": [
{
"leaf21": 3
}
]
},
{
"root3": [
{
"leaf31": "somestring"
},
{
"index": "foundit"
}
]
}
]
}
具体来说:如果有一个 JSON 文档和一个像 "root" -> "root3" -> "index" 这样的路径存在,我想 return"foundit",否则我想return没什么。文档中的其他所有内容都是任意的:root3、root2、root1、root 可能存在也可能不存在等。
现在我可以使用大量 case 语句和模式匹配来做到这一点,但在阅读 https://wiki.haskell.org/All_About_Monads 之后,我想知道是否有更好的方法使用类似于 Maybe Monad 和绵羊克隆示例的方法,但是我不确定如何编写绑定函数...
[在我的真实案例中,我寻求的价值实际上在文档中有 19 个深度,所以我有很多案例陈述]
请问您能否建议如何使用 Monad 来做到这一点?
是的,不需要那些 case
语句
您的猜测是正确的 - 但在这种情况下单子不是正确答案(没有双关语意1)。
这对 Traversals
、Prisms
和 Lenses
来说是一项伟大的工作 - 当然还有伟大的 aeson-library and 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"
那么这是做什么的?
decode
将ByteString
转换为Maybe Value
-Maybe
因为解析可能会失败!然后
(^?)
运算符预览遍历 - 即它通过 JSON 对象并遵循您提供的 json 路径;
为此你至少要知道通往 "index" 的路径,如果这条路径未知,你必须对 lenses/prisms/traversals 投入更多的研究或进行简单的树搜索在解析的对象上。
这里有一个剧透,供那些没有时间在 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: 好吧,也许有点