使用镜头将键和值添加到嵌套地图

Using lens to add key and value to a nested Map

我正在努力解决使用 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}}"

当然是我做错了什么,但我想我已经没法理解到底是什么了。

你能给我指出正确的方向吗?

谢谢!

key 基于 ix,其文档表明它不够强大,无法执行您想要的操作并指向 Control.Lens.At.at。我很确定这应该对你有用。基本思想是,您从 _Object 棱镜开始,将 JSON 文本变成一个对象,然后使用 at key 将透镜 作为 Maybe。然后,您可以将其更改为 Just 您想要的。

只要您要走的路径上的所有对象都存在,这将非常有效。如果您想(可能)从无到有并创建一个 single-field 对象链,您可能会发现事情更烦人。幸运的是,您可能不需要这样做。

正如 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"