Lens & aeson: setting a key’s value based on another key - Haskell

Welcome to the Functional Programming Zulip Chat Archive. You can join the chat here.

Magnus Therning

I’m trying to work out if there’s a nicer way (i.e. more clever) of using lens-aeson to set a key based on the value of another key.

I have a YAML structure like this:

yaml' :: Value
yaml' =
    [yamlQQ|
- panda:
    x-image: panda
- goat:
    x-image: goat
|]

that I want to transform into this:

yaml' :: Value
yaml' =
    [yamlQQ|
- panda:
    image: panda:latest
    x-image: pada
- goat:
    image: goat:latest
    x-image: goat
|]

That is, I want to add/set the value of image based on the value of x-image of the same object.

The way I came up with was to write a helper function

foo o = o & _Object . at "image" ?~ String (iN <> ":latest")
  where
    iN = o ^. key "x-image" . _String

and using that I can do what I want:

λ> yaml' & values . members %~ foo
Array [Object (fromList [("panda",Object (fromList [("image",String "panda:latest"),("x-image",String "panda")]))]),Object (fromList [("goat",Object (fromList [("image",String "goat:latest"),("x-image",String "goat")]))])]

Is there another, nicer way of doing this?

rhendric

Would you consider this nicer?

yaml' & values . members . _Object %~ (set (at "image") . (_Just . _String %~ (<> ":latest")) =<< view (at "x-image"))
Magnus Therning

Hmm, maybe slightly. I have to admit I was hoping I'd missed a function that perfectly fit my need though :sweat_smile: