Использование объектива для добавления ключа и значения в вложенную карту

Я изо всех сил пытаюсь разобраться с проблемой манипулирования JSON объективами Aeson. Моя задача так же просто, как добавить ключ к вложенному объекту в JSON. Я смог изменить существующие keyby способами:

> :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}}"

Конечно, это я делаю что-то неправильно, но я полагаю, что я не в мане, чтобы понять, что именно.

Не могли бы вы указать мне в правильном направлении?

Спасибо!

Ответ 1

Как отметил dfeuer, at может вставляться в карты, а key и ix просто пересекают элементы, если они существуют. Мы можем сделать следующее:

> "{ \"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"

Ответ 2

key основан на ix, документация которого указывает, что он недостаточно мощный, чтобы делать то, что вы хотите, и указывает на Control.Lens.At.at. Я почти уверен, что должен сделать трюк для вас. Основная идея заключается в том, что вы начинаете с призмы _Object, чтобы превратить текст JSON в объект, а затем используйте at key, чтобы получить объектив в этом поле как Maybe. Затем вы можете изменить его на Just, что вы хотите.

Это будет работать очень хорошо, если все объекты вдоль пути, который вы хотите использовать, существуют. Если вы хотите (потенциально) начать с нуля и создать цепочку однопольных объектов, вы, скорее всего, найдете вещи более раздражающими. К счастью, вам, вероятно, не нужно это делать.