Using Lens in Haskell to modify values

haskell, haskell-lens, lenses

Solution

You can use a chain of `Lens`es and `Traversal`s to access the inner header value directly and update it.

put $ mail & headers . at header ?~ value

Note that `(?~)` is just shorthand for `\lens value -> lens .~ Just value`. The `Just` is needed to indicate to the `at` lens that we want to insert a value if it doesn't exist already.

If `mail` in the first line comes from the state monad like this

do
  mail <- get
  let oldHeaders = mail ^. headers
  put $ (headers .~ (insert header value oldHeaders)) mail

then it's simpler to write that with `modify :: MonadState s m => (s -> s) -> m ()`

modify (headers . at header ?~ value)

Which, as suggested by Ørjan Johansen in the comments, can be written most pithily as

headers . at header ?= value

Problem

I find myself using this pattern often: ``` do let oldHeaders = mail ^. headers put $ (headers .~ (insert header value oldHeaders)) mail ``` which seems like the kind of thing Control.Lens should be able to do, but I guess I just haven't found the right operator yet. Is there a better way? Also, is there anything else I should be doing differently in this code?

Original source