标准Haskell函数::(a - >可能b) - > [a] - >也许b

时间:2013-10-28 19:41:36

标签: haskell

如果F#返回第一个(从左到右,如果有的话)成功应用列表元素的函数,则有一个标准的tryPick函数。我正在跳跃有一个像Haskell那样的标准函数。我tried Hoogle并没有找到任何结果。

我是Haskell的新手,我不确定这样做的正确方法是什么。你会这样做吗:

tryPick:: (a -> Maybe b) -> [a] -> Maybe b
tryPick try xs = case Maybe.mapMaybe try xs of
    [] -> Nothing
    (x:_) -> Just x

4 个答案:

答案 0 :(得分:15)

你想:

tryPick :: (a -> Maybe b) -> [a] -> Maybe b
tryPick f as = msum (map f as)

我会解释这是如何运作的。

map f as会生成一系列可能的Maybe操作:

map f as :: [Maybe b]

msum按顺序尝试它们直到成功(将值作为Just返回)或者它们都失败(返回Nothing)。例如:

> msum [Nothing, Just 2, Just 3, Nothing]
Just 2
> msum [Nothing, Nothing]
Nothing

请注意,msum的类型更为通用,因此我们可以将签名概括为:

tryPick :: (MonadPlus m) => (a -> m b) -> [a] -> m b

这将适用于任何MonadPlus。有趣地发现它对其他MonadPlus类型的作用。

答案 1 :(得分:14)

listToMaybe中的Data.Maybe功能看起来非常不错:

tryPick f = listToMaybe . mapMaybe f

答案 2 :(得分:12)

这不一定是最简单的解决方案,但我认为突出基于First Monoid的解决方案很重要。我认为这是最漂亮的。

import Data.Monoid
import Data.Foldable (Foldable, foldMap)

tryPick :: (a -> Maybe b) -> [a] -> Maybe b
tryPick f = getFirst . foldMap (First . f)     -- this is just `foldMap f`
                                               -- with the "firsty" Maybe Monoid

这也可以立即推广到具有完全相同代码的任何Foldable

tryPick :: Foldable t => (a -> Maybe b) -> t a -> Maybe b

Foldable个实例提供了使用Monoid将所有元素“粉碎”在一起的方法。 First Monoid定义为

newtype First a = First { getFirst :: Maybe a }

Maybe的特化,其mappend操作可选择“第一个”或“最左侧”Just

所以,将它们组合在一起,getFirst . foldMap (First . f)会在(a -> Maybe b)中的所有a上计算您的[a]函数,然后将结果与规则一起打破“第一次”Just获胜。

答案 3 :(得分:8)

我来参加派对有点晚了,但这里有一个关于J. Abrahamson答案的变体,它使用了newtype package中的Conor McBride可爱的ala'函数:

import Control.Newtype (ala')
import Data.Foldable (Foldable, foldMap)
import Data.Monoid (First(..))

tryPick :: (Foldable t) => (a -> Maybe b) -> t a -> Maybe b
tryPick = ala' First foldMap

这可能看起来有点神秘,但我发现它将“收集容器”(First)从“收集方案”(foldMap)和“预处理功能”中解耦的方式(a -> Maybe b) - 同时隐藏newtype包裹和展开 - 相当漂亮。 ala在我的经验中是创建漂亮代码的好工具,我想插上它。谢谢,康纳!