【发布时间】:2021-06-02 09:26:03
【问题描述】:
假设我有一个函数表示一些可能失败的计算
f :: a -> Maybe b
如果我有一个列表l,我可以使用findList f l 在列表中找到f 成功的第一个(从左到右扫描时)项目,其中findList 是以下函数
findList :: (a -> Maybe b) -> [a] -> Maybe b
findList f [] = Nothing
findList f (x : xs) = case f x of
Nothing -> findList f xs
Just y -> Just y
(或使用,例如,extra 包中的 firstJust)。
问题。
如果我想用来自containers 的Set 做同样的事情该怎么办?
也就是说,我想要一个带签名的函数
findSet :: (a -> Maybe b) -> Set a -> Maybe b
相当于
findSet f s = findList f (Set.toList s)
上面的行作为一个实现。但是,我不想创建中间列表Set.toList s(即使使用惰性求值,仍然存在一些不必要的开销,对吧?)。
一旦找到成功的项目,我也不想遍历整个集合,如以下实现所示:
findSet f s = foldl g Nothing s
where
g Nothing x = f x
g (Just y) _ = Just y
那么有没有一种好方法可以遍历一个“从左到右”的集合,对每个成员应用一个可能失败的计算,然后在第一个成功的结果处停止?
【问题讨论】:
-
当使用第二个参数不严格的 reducer 函数调用时,
foldr从左到右工作。你的第一个函数是\f -> listToMaybe . mapMaybe f :: (a1 -> Maybe a) -> [a1] -> Maybe a,第二个函数是\f -> listToMaybe . mapMaybe f . toList :: Foldable t => (a1 -> Maybe a) -> t a1 -> Maybe a。如果您的数据类型的Foldable实例定义了惰性的toList,则开销应该很小,如果有的话。