如果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
答案 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
在我的经验中是创建漂亮代码的好工具,我想插上它。谢谢,康纳!