Using a lens in Haskell to change values

I often use this template:

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

which looks like a Control.Lens thing should be able to do, but I think I haven't found the right operator yet. Is there a better way? Also, is there anything else I should do differently in this code?

+6
source share
2 answers

You can use the Lens es and Traversal chain to directly access the internal value of the header and update it.

 put $ mail & headers . at header ?~ value 

Note that (?~) Is simply abbreviated for \lens value -> lens .~ Just value . Just needs to point to the at object we want to insert if it does not already exist.

If the mail in the first line comes from a state monad, such as

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

it’s easier to write that with modify :: MonadState sm => (s -> s) -> m ()

 modify (headers . at header ?~ value) 

Which, as suggested by Γ–rjan Johansen in the comments, can be written most reliably as

 headers . at header ?= value 
+10
source

Usually you do not need to get and put in the State monad when using lenses. In your case, you can use the ?= Operator to update the status immediately:

 example = do headers . at header ?= value 

You can also change any lens using the %= function:

 example2 = do headers %= insert header value 
+7
source

All Articles