Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 提取Aeson对象内的嵌套属性_Haskell_Aeson - Fatal编程技术网

Haskell 提取Aeson对象内的嵌套属性

Haskell 提取Aeson对象内的嵌套属性,haskell,aeson,Haskell,Aeson,如何使用Data.Aeson获取嵌套属性 例如,当使用如下值解码任意JSON字符串时: decode "{\"foo\":{\"bar0\":\"foobar0\", \"bar1\":\"foobar1\"}}" :: Maybe Value 我的结论是: Just (Object (fromList [("foo",Object (fromList [("bar1",String "foobar1"),("bar0",String "foobar0")]

如何使用Data.Aeson获取嵌套属性

例如,当使用如下值解码任意JSON字符串时:

decode "{\"foo\":{\"bar0\":\"foobar0\",
                  \"bar1\":\"foobar1\"}}" :: Maybe Value
我的结论是:

Just (Object (fromList [("foo",Object (fromList [("bar1",String "foobar1"),("bar0",String "foobar0")]))]))
现在,我如何编写一个函数[String]->Object->Maybe Value来提取通过提供的属性列表得到的值(如果有的话)

此函数的使用方式如下:

extractProperty ["foo", "bar0"] (Object (fromList [("foo",Object (fromList [("bar1",String "foobar1"),("bar0",String "foobar0")]))]))

==> Just (String "foobar0")

extractProperty ["foo", "bar0", "baz"] (Object (fromList [("foo",Object (fromList [("bar1",String "foobar1"),("bar0",String "foobar0")]))]))

==> Nothing

以下解决方案使用了lens和lens aeson软件包:

{-# LANGUAGE FlexibleInstances #-}

import Control.Lens (view,pre,ix)        -- from lens
import Control.Lens.Reified (ReifiedTraversal(..))
import Data.Aeson           -- from aeson
import Data.Aeson.Lens (_Object)  -- from lens-aeson
import Data.Text            -- form text

instance Monoid (ReifiedTraversal s s s s) where
    mempty = Traversal id
    mappend (Traversal t1) (Traversal t2) = Traversal (t1 . t2) 

extractProperty :: [Text] -> Object -> Maybe Value 
extractProperty keys o = 
    view (pre telescope) (Object o)
  where
    telescope = runTraversal $ foldMap (\k -> Traversal $ _Object . ix k) keys
ReifiedTraversal只是一个围绕遍历的新类型,我们在它上面定义了一个Monoid实例,以允许轻松组合以相同类型开始和结束的遍历,类似于Monoid的工作方式

在我们的例子中,遍历对象。IXK从一个值到另一个值。来自Control.Lens.At和对象属性映射上的索引

我们提取组合遍历的第一个结果(如果它与函数一起存在)

编辑:@cchalmers在他的评论中提到,不需要声明孤立实例,只需使用Endo就可以了。此外,键k与_对象相同。IXK

以下是extractProperty的一个版本,它不使用lens,而是依赖于使用foldr组成kleisli箭头值->可能值的列表:


在这种情况下,镜头可能有点过火了。

另一种方法,使用一元绑定:

import Data.Text (Text)
import qualified Data.HashMap.Strict as HM

extractProperty :: [Text] -> Value -> Maybe Value
extractProperty []     v          = Just v
extractProperty (k:ks) (Object o) = HM.lookup k o >>= prop ks
extractProperty _      _          = Nothing

为什么不直接使用Endo而不是编写一个误导性的孤儿?也反对。ix k=键i。这里有一个更简洁的版本extract ks=预览alaf Endo foldMap key ks。物体。这很优雅,但可能是因为我还没有学过镜头,所以看起来有些过分了。有没有一个更简单、可能是递归的解决方案?@cchalmers你能在一个新的答案中扩展你的建议吗?@cchalmers我有一个错误的印象,即Endo不能很好地处理遍历/镜头。
import Data.Text (Text)
import qualified Data.HashMap.Strict as HM

extractProperty :: [Text] -> Value -> Maybe Value
extractProperty []     v          = Just v
extractProperty (k:ks) (Object o) = HM.lookup k o >>= prop ks
extractProperty _      _          = Nothing