我们说我有一个列表[A]
。如果满足某些谓词,我想更新列表的特定元素。但如果没有这样的元素,我想先将元素添加到列表中。我目前的解决方案是手动编写将元素插入列表的函数(如果它不存在)然后使用filtered
遍历来更新我的元素。像这样:
-- 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
我想知道是否有更好(更短,更惯用)的解决方案?如果可能的话,我会很感激只使用microlens
系列软件包的解决方案。
答案 0 :(得分:0)
你应该可以使用has
来缩短它:
functionIWantToWrite :: [A] -> [A]
functionIWantToWrite = modifyItem . addEmptyItem
where
_items = filtered myPredicate
addEmptyItem list | has _items list = list
| otherwise = item : list
modifyItem = each . _items %~ myUpdate
如果您真的想缩短它,您可以使用Monoid m => Applicative (m,)
实例左右将其作为单个遍历来获取,例如
accAny :: (x -> Bool) -> (x -> x) -> x -> (Any, x)
accAny pred fn x = (Any b, if b then fn x else x)
where b = pred x
functionIWantToWrite list = handle . traverse . accAny myPredicate myUpdate $ list
where handle (Any True, list) = list
handle (_, list) = item : list