组合设置器镜头的语法是什么?

3

我刚接触镜头(Lens)技术,我想将两个“setter”操作组合起来,使其等效于从state0到new_state2的转换:

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

这该怎么做的语法是什么?

1
我也强烈推荐这篇阅读材料 - Bartek Banachewicz
1个回答

6
有趣的是,镜头和函数非常相似:都使用(.)进行组合:
setterAB :: Lens' A B
setterBC :: Lens' B C

setterAC = setterAB . setterBC

在你的例子中,你不需要组合镜头(lens);你需要组合转换(transformation)(既是镜头又是实际操作),有两种方法可以实现。
哦,在我们开始之前,让我们简化一下你的代码,使用`.~`(“设置”)而不是`%~`(“修改”):
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,你可以完全摆脱那个传递,并将其放入单子中:

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

它们是基于MonadState定义的,因此如果您在一个monad堆栈中,您可以直接使用那个实例,或者使用StateT以便为setter提供更多的效果。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接