使用镜头为嵌套Map

时间:2015-12-29 12:33:04

标签: haskell lens aeson lenses

我正在努力解决使用Aeson镜头操纵JSON的问题。我的任务就像在JSON中向嵌套对象添加密钥一样简单。我能够通过以下方式更改现有密钥:

> :set -XOverloadedStrings
> import Control.Lens
> import Data.Aeson
> import Data.Aeson.Lens
> "{ \"a\": { \"b\": 10 } }" & key "a" . key "b" .~ String "jee"
"{\"a\":{\"b\":\"jee\"}}"

但是当我尝试让它处理新密钥时,它只是默默地无法添加它:

> "{ \"a\": { \"b\": 10 } }" & key "a" . key "c" .~ String "jee"   
"{\"a\":{\"b\":10}}"

当然,这是我做错了什么,但我认为我已经达不到法术力量。

请您指出我正确的方向吗?

谢谢!

2 个答案:

答案 0 :(得分:17)

正如dfeuer所指出的,at可以插入到地图中,而keyix只会遍历元素(如果存在)。我们可以做到以下几点:

> "{ \"a\": { \"b\": 10 } }" & key "a" . _Object . at "c" ?~ String "foo"
"{\"a\":{\"b\":10,\"c\":\"foo\"}}

at是专注于Maybe element - s的镜头,我们可以通过设置为Just某个元素来插入,并通过设置为Nothing来删除。 at "c" ?~ String "foo"at "c" .~ Just (String "foo")相同。

如果我们想要嵌套插入,我们可以使用non来定义要插入的默认值:

> "{ \"a\": { \"b\": 10 } }" & key "a" . _Object . at "c" . non (Object mempty) . _Object . at "d" ?~ String "foo"
"{\"a\":{\"b\":10,\"c\":{\"d\":\"foo\"}}}"

这是一个满口的,所以我们可以考虑一些部分:

> let atKey k = _Object . at k
> "{ \"a\": { \"b\": 10 } }" & key "a" . atKey "c" . non (Object mempty) . atKey "d" ?~ String "foo"

答案 1 :(得分:3)

ix基于Control.Lens.At.at,其文档表明它不足以执行您想要的操作并指向_Object。我很确定应该为你做的伎俩。基本的想法是,您从at key棱镜开始将JSON文本转换为对象,然后使用Maybe将镜头作为Just 进入该字段 EM>。然后,您可以将其更改为{{1}}您想要的内容。

只要您想要采用的路径上的所有对象都存在,这将非常有效。如果你想(可能)从零开始并创建一个单场对象链,你可能会发现更烦人的事情。幸运的是,你可能不需要这样做。