使用镜头按索引访问矢量元素

Accessing vector element by index using lens

我正在寻找一种使用镜头库引用矢量元素的方法...

让我尝试使用我的代码的简化示例来解释我要实现的目标。

我在这个 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)])

现在,这就是我要找的东西:我希望我的函数接收到我感兴趣的客户端的 "reference" 并使用它(从 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

基本上,我想从 Lens 库中向 myFunction 传递一些东西(我不知道我在这里传递的是什么...... Lens?遍历?获取?其他一些东西?)这将使我能够指出在我的 StateT 中保存的向量中的特定元素处。有可能吗?目前,在使用 "clients.ix 0" 时出现错误,提示我的 ClientT 不是 Monoid 的实例。

这是我所拥有的一个非常简单的版本。为了回答问题 "why I need it this way" 需要更多的解释。我很感兴趣是否可以传递这个 "reference" 它将指向我的向量中保存在 State 中的某个元素。

clients.ix 0是遍历。特别是,遍历是设置器,因此设置和修改应该可以正常工作:

clients.ix 0 .= updatedClient

您的问题出在 use 上。因为遍历不一定只包含一个值,所以当您 use 遍历(或在其上使用其他 getter 函数)时,它会合并所有值,假设它们属于 Monoid类型。

特别是,

use (clients.ix n)

想要return mempty 如果n 超出范围。

相反,您可以使用 preuse 函数,它丢弃遍历的 first 目标以外的所有目标(或更一般地说,折叠),并将其包装在Maybe。例如

Just c <- preuse (clients.ix n)

请注意,如果 n 超出范围,这将给出模式匹配错误,因为 preuse returns Nothing 那么。