【问题标题】:How to add element to list if it's not there with 'lens'?如果“镜头”不存在,如何将元素添加到列表中?
【发布时间】:2018-03-05 12:45:13
【问题描述】:

假设我有一个列表[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

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

【问题讨论】:

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

标签: list haskell haskell-lens


【解决方案1】:

您应该可以使用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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-01
    • 2019-09-22
    • 2018-03-07
    • 2020-10-25
    • 2017-03-31
    • 1970-01-01
    相关资源
    最近更新 更多