在Haskell中使用Lens来修改值

Dre*_*rew 7 haskell lenses haskell-lens

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

do
    let oldHeaders = mail ^. headers
    put $ (headers .~ (insert header value oldHeaders)) mail
Run Code Online (Sandbox Code Playgroud)

这看起来像Control.Lens应该能做的事情,但我想我还没有找到合适的操作员.有没有更好的办法?另外,在这段代码中我还应该做些什么吗?

J. *_*son 11

您可以使用Lenses和Traversals 链直接访问内部标头值并更新它.

put $ mail & headers . at header ?~ value
Run Code Online (Sandbox Code Playgroud)

请注意,这(?~)只是简写\lens value -> lens .~ Just value.的Just是需要指出的at是,我们想,如果不存在的话插入值镜头.

如果mail在第一行来自像这样的州monad

do
  mail <- get
  let oldHeaders = mail ^. headers
  put $ (headers .~ (insert header value oldHeaders)) mail
Run Code Online (Sandbox Code Playgroud)

然后用它来写它就更简单了 modify :: MonadState s m => (s -> s) -> m ()

modify (headers . at header ?~ value)
Run Code Online (Sandbox Code Playgroud)

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

headers . at header ?= value
Run Code Online (Sandbox Code Playgroud)

  • (试图使这个编辑但被拒绝:)记住许多以`~`结尾的纯生成器操作符都有以`=`结尾的monadic状态更新版本,我们可以组合`?~`和modify:`headers .在标题?=值` (4认同)

sha*_*ang 7

你通常不会需要getput明确在State使用镜头时单子.在您的情况下,您可以使用运算符?=直接更新状态:

example = do
  headers . at header ?= value
Run Code Online (Sandbox Code Playgroud)

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

example2 = do
  headers %= insert header value
Run Code Online (Sandbox Code Playgroud)