构成 setter 镜头的语法是什么?

What is the syntax for composing setter lenses?

我是 lens 的新手,我想编写两个 "setter" 操作等效于此状态 0 到 new_state2 转换:

  let new_state1 = field1 %~ (const newVal1) $ state0
  let new_state2 = field2 %~ (const newVal2) $ new_state1

这样做的语法是什么?

有趣的是,镜头的组成就像功能一样:(.):

setterAB :: Lens' A B
setterBC :: Lens' B C

setterAC = setterAB . setterBC

不过,在您的示例中,您不想合成镜头;你想组合transformations(既是镜头又是实际操作),有两种方法可以做到。

哦,在我们真正开始之前,让我们稍微简化一下您的代码,使用 (.~) ("set") 而不是 (%~) ("modify"):

let new_state1 = field1 .~ newVal1 $ state0
let new_state2 = field2 .~ newVal2 $ new_state1

直接,通过 &

有一个奇特的 & 运算符,效果很好。只是 flip ($):

let new_state1 = state0 & field1 .~ newVal1
let new_state2 = new_state & field2 .~ newVal2

这意味着您现在可以写:

let new_state = 
    state0 
        & field1 .~ newVal1
        & field2 .~ newVal2

单子

更好的是,如果你实际上在某个地方有一个 State,你可以完全摆脱那个传递并将它放在一个 monad 中:

let new_state = (flip execState state0) $ do
    field1 .= newVal1
    field2 .= newVal2

它们是根据 MonadState 定义的,因此如果您在 monad 堆栈中,则可以直接使用该实例,或使用 StateT 以获得更多可用效果二传手。