遍历Data.Set直到成功 [英] Iterating over a Data.Set until success

查看:56
本文介绍了遍历Data.Set直到成功的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有一个表示某些可能会失败的计算的函数

Suppose I have a function representing some computation that can fail

f :: a -> Maybe b

如果我有一个列表 l ,我可以找到列表中的第一个(当从左向右扫描时) f 成功使用的项目findList fl ,其中 findList 是以下函数

If I have a list l, I can find the first (when scanning left-to-right) item in the list on which f succeeds using findList f l, where findList is the following function

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

(或使用例如

(or using, e.g., firstJust from the extra package).

如果我想对 设置 ?

What do I do if I want to do the same thing with a Set from containers?

也就是说,我想要一个带有签名的功能

That is, I want a function with signature

findSet :: (a -> Maybe b) -> Set a -> Maybe b

等效于

findSet f s = findList f (Set.toList s)

上面的行用作实现.但是,我不想创建中间列表 Set.toList s (即使使用惰性评估,仍然会有一些不必要的开销,对吧?).

The line above works as an implementation. However, I don't want to create the intermediate list Set.toList s (even with lazy evaluation, there is still some unnecessary overhead, right?).

一旦找到成功的项目,我也不想遍历整个集合,如以下实现所示:

I also don't want to iterate over the entire set once a successful item has been found, as in the following implementation:

findSet f s = foldl g Nothing s
  where
    g Nothing x = f x
    g (Just y) _ = Just y

那么,有没有一种好的方法来遍历一组从左到右",对每个成员应用可能失败的计算,并在第一个成功的结果处停止?

So is there a good way of traversing over a set "left-to-right", applying a computation that can fail to each member, and stopping at the first successful result?

推荐答案

您可以使用 Set Foldable 的实例这一事实.因此,您可以通过以下方式实现 Fold 函数:

You can work with the fact that the Set is an instance of Foldable. You can thus implement a Fold function with:

import Control.Applicative((<|>))

findSet :: (a -> Maybe b) -> Set a -> Maybe b
findSet f = foldr ((<|>) . f) Nothing

这实际上可以与 Foldable 的所有实例一起使用:

this can in fact work with all instances of Foldable:

import Control.Applicative((<|>))

findSet :: (Alternative g, Foldable f) => (a -> g b) -> f a -> g b
findSet f = foldr ((<|>) . f) Nothing

@DanielWagner说,我们可以使用 First ,因为 First 将选择第一个 Just ,因此可以使用:

or as @DanielWagner says, we can make use of First, since First will select the first Just, and thus work with:

import Control.Applicative((<|>))

findSet :: Foldable f => (a -> Maybe b) -> f a -> Maybe b
findSet f = getFirst . foldMap (First . f)

tolist 的实现也可以通过 Foldable 来实现:

The implementation of toList is also implemented in terms of Foldable:

toList :: Foldable f => f a -> [a]
toList = foldr (:) []

所以我们在这里要做的不是先将其包装在一个弊端中,然后再将其拆开,立即应用 f 并使用

so what we here do is instead of first wrapping it in a cons and then unwrap it, immediately apply f and work with the implementation of (<|>) :: Alternate f => f a -> f a -> f a.

这篇关于遍历Data.Set直到成功的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆