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

Tri*_*Gao 13 haskell

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

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

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

Gab*_*lez 15

你要:

tryPick :: (a -> Maybe b) -> [a] -> Maybe b
tryPick f as = msum (map f as)
Run Code Online (Sandbox Code Playgroud)

我将解释它是如何工作的.

map f as生成可能的Maybe操作列表:

map f as :: [Maybe b]
Run Code Online (Sandbox Code Playgroud)

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

> msum [Nothing, Just 2, Just 3, Nothing]
Just 2
> msum [Nothing, Nothing]
Nothing
Run Code Online (Sandbox Code Playgroud)

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

tryPick :: (MonadPlus m) => (a -> m b) -> [a] -> m b
Run Code Online (Sandbox Code Playgroud)

这将适用于任何人MonadPlus.玩得开心,发现它对其他MonadPlus类型的作用.


Jos*_*Lee 14

listToMaybe函数Data.Maybe看起来很不错:

tryPick f = listToMaybe . mapMaybe f
Run Code Online (Sandbox Code Playgroud)


J. *_*son 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
Run Code Online (Sandbox Code Playgroud)

对于Foldable具有完全相同代码的任何一个,这也可以立即推广

tryPick :: Foldable t => (a -> Maybe b) -> t a -> Maybe b
Run Code Online (Sandbox Code Playgroud)

Foldable实例提供了使用Monoids 将所有元素"粉碎"在一起的方法.该First Monoid定义为

newtype First a = First { getFirst :: Maybe a }
Run Code Online (Sandbox Code Playgroud)

是一个选择"第一"或"最左" Maybemappend操作的专业化Just.

因此,将它们放在一起,getFirst . foldMap (First . f)计算你(a -> Maybe b)对所有as中的函数[a],然后将结果与"第一" Just获胜的规则一起打破.


Aar*_*oth 8

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

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
Run Code Online (Sandbox Code Playgroud)

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