我正在寻找一种使用镜头库来引用矢量元素的方法......
让我试着用我的代码的简化示例来解释我想要实现的目标。
我在这个monad变换器堆栈中工作(其中StateT是焦点,其他一切都不重要)
newtype MyType a = MyType (StateT MyState (ExceptT String IO) a)
MyState 有很多字段,但其中一个是客户端的向量,它是我定义的数据类型:
data MyState = MyState { ...
, _clients :: V.Vector ClientT
}
每当我需要访问我的一个客户时,我倾向于这样做:
import Control.Lens (use)
c <- use clients
let neededClient = c V.! someIndex
... -- calculate something, update client if needed
clients %= (V.// [(someIndex, updatedClient)])
现在,我正在寻找的是:我希望我的功能能够获得&#34;参考&#34;对我感兴趣并使用它的客户(从State检索它,如果需要更新它)。
为了清楚我的意思,这里是一个片段(即使在伪代码中也不会编译):
...
myFunction (clients.ix 0)
...
myFunction clientLens = do
c <- use clientLens -- I would like to access a client in the vector
... -- calculate stuff
clientLens .= updatedClient
基本上,我想从镜头库传递给myFunction一些东西(我不知道我在这里经过什么......镜头?遍历?得到?其他一些东西?)这将允许我指向保存在StateT中的向量中的特定元素。它可能吗?目前,当使用&#34; clients.ix 0&#34;我收到一个错误,我的ClientT不是Monoid的实例。
这是我所拥有的非常愚蠢的版本。为了回答问题&#34;为什么我需要这种方式&#34;需要更多解释。如果有可能通过这个&#34;参考&#34;我感兴趣这将指向我的矢量中保存在状态中的某个元素。
答案 0 :(得分:3)
clients.ix 0
是一次遍历。特别是,遍历是设置器,因此设置和修改应该可以正常工作:
clients.ix 0 .= updatedClient
您的问题出在use
。因为遍历并不一定只包含一个值,所以当您use
遍历(或使用其他一些其他getter函数)时,它会结合所有值,假设它们是Monoid
类型
特别是
use (clients.ix n)
如果mempty
超出范围,会希望返回n
。
相反,您可以使用preuse
函数,该函数会丢弃除遍历的第一个目标之外的所有目标(或更常见的是折叠),并将其包装在{{1 }}。 E.g。
Maybe
请注意,如果Just c <- preuse (clients.ix n)
超出界限,则会出现模式匹配错误,因为n
会返回preuse
。