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