我有一些
行的数据类型data Outer = Outer { _list :: [ Inner ] }
data Inner = Inner { _bool :: Bool }
使用Control.Lens,我可以像这样访问第i个内部的_bool(在'State Outer'monad中)
boolValue <- gets (^. list . to (!! i) . inner)
我也想用
之类的东西来更新这个值list ^. (to (!! i)) ^. inner %= True
然而(根据我的理解),'to'功能只会创建一个getter,而不是一个可以用作getter或setter的真镜头。
那么,我怎样才能将(!! i)转换为允许我更新此字段的镜头?
答案 0 :(得分:17)
除了(!!)
之外,你不能将Getter
变成任何类似镜头的东西 - 但是有一个功能可以做这样的事情:ix,用于访问事物在指数。它实际上是Traversal
,而不是Lens
- 这里,只是意味着它可能失败(如果索引超出范围) - 但只要索引在列表中,它会起作用。
还有另一个问题 - (^.)
也是一个专门用于获取值的运算符。它与例如不相容(%=)
,它将镜头般的东西作为第一个参数。并且:(%=)
用于将函数映射到现有值;如果您只想设置,可以使用(.=)
。所以你可能想要这样的东西:
list . ix i . inner .= True
*实际上有一个功能可以做到这一点 - 它被称为upon
- 但它使用了奇妙的邪恶黑魔法而你不应该使用它,至少不是为了这个(并且可能不适用于此)真实的代码)。
答案 1 :(得分:9)
使用element
,它是指定列表元素的Traversal
:
list . element i . inner %= True :: Outer -> Outer
如果要获取list元素,必须使用Maybe
,因为list元素可能不在那里:
myList :: Outer
myList ^? list . element i . inner :: Maybe Bool