List 如果元素为';与';镜头';?

List 如果元素为';与';镜头';?,list,haskell,haskell-lens,List,Haskell,Haskell Lens,假设我有一个列表[a]。我想更新列表的特定元素,如果它满足某个谓词。但若并没有这样的元素,我想先将元素添加到列表中。我目前的解决方案是手动编写函数,以便在列表中不存在元素时将其插入列表中,然后使用filteredTraversal更新我的元素。像这样: -- inserts element to list if there's no a single element -- which satisfies given predicate insertIfNot :: (a -> Bool

假设我有一个列表
[a]
。我想更新列表的特定元素,如果它满足某个谓词。但若并没有这样的元素,我想先将元素添加到列表中。我目前的解决方案是手动编写函数,以便在列表中不存在元素时将其插入列表中,然后使用
filtered
Traversal更新我的元素。像这样:

-- inserts element to list if there's no a single element 
-- which satisfies given predicate 
insertIfNot :: (a -> Bool) -> a -> [a] -> [a]
insertIfNot _ e []       = [e]
insertIfNot p e l@(x:xs) = if p x then l else x : insertIfNot p e xs

functionIWantToWrite :: [A] -> [A]
functionIWantToWrite = modifyItem . addEmptyItem
  where
    addEmptyItem = insertIfNot myPredicate item
    modifyItem   = each.filtered myPredicate %~ myUpdate

我想知道是否有更好(更短、更惯用)的解决方案?如果可能的话,我将非常感谢只使用软件包系列的解决方案。

您应该能够使用
has
将其缩短一点:

functionIWantToWrite::[A]->[A]
functionIWantToWrite=modifyItem。附加项
哪里
_items=筛选的myPredicate
addEmptyItem list | has _itemslist=列表
|否则=项:列表
modifyItem=每个_项目更新
如果您真的想缩短它,那么您可以使用
monoidm=>Applicative(m,)
实例等将其作为一次遍历来获得,比如

accAny::(x->Bool)->(x->x)->x->(任意,x)
accAny pred fn x=(任意b,如果是b,则为fn x,否则为x)
其中b=pred x
functionIWantToWrite列表=句柄。穿过accAny myPredicate myUpdate$列表
其中handle(任意True,list)=list
句柄(_,列表)=项:列表

@chepner非常接近,但并不准确。正如你们所看到的,我使用的是列表,所以效率并不是我的首要任务。虽然我认为我的解决方案已经足够有效,甚至可能只使用一次遍历列表。我想要较短的格式(没有效率的大损失)。我对使用镜头的解决方案很感兴趣(因为没有镜头我可以自己做)。不同之处在于,在您的表单中,
myUpdate
应检查是否修改元素,而在我的表单中,
map myUpdate
将更改列表中的每个元素。但是你的想法很接近我想要的。哦,对不起。我知道你真正想要什么,然后忘了删除我的评论。