7

我发现自己经常使用这种模式:

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

这似乎是 Control.Lens 应该能够做的事情,但我想我还没有找到合适的操作员。有没有更好的办法?另外,在这段代码中我还应该做些什么不同的事情吗?

4

2 回答 2

11

您可以使用Lenses 和Traversals 链直接访问内部标头值并对其进行更新。

put $ mail & headers . at header ?~ value

请注意,这(?~)只是\lens value -> lens .~ Just value. Just需要向镜头指示我们at要插入一个值(如果它尚不存在)。

如果mail第一行来自这样的状态单子

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

那么用modify :: MonadState s m => (s -> s) -> m ()

modify (headers . at header ?~ value)

正如 Ørjan Johansen 在评论中所建议的那样,可以最简洁地写成

headers . at header ?= value
于 2014-01-13T05:10:38.327 回答
7

使用镜头时,您通常不需要get并且put明确地在monad 中。State在您的情况下,您可以使用运算符?=直接更新状态:

example = do
  headers . at header ?= value

您还可以使用以下功能修改任何镜头%=

example2 = do
  headers %= insert header value
于 2014-01-13T07:26:33.877 回答