Haskell 使用mplus创建函数列表

Haskell 使用mplus创建函数列表,haskell,Haskell,如何使用。我希望具有类似的效果,但将函数列表作为参数: tryFuncs :: [a -> Maybe b] -> a -> Maybe b ... 那么一个像这样的电话 tryFuncs [f, g, h] x 将成为可能,并按照 (f x) `mplus` (g x) `mplus` (h x) 如何实现这一点?最简单的方法是将msum(mplus的列表版本)与map一起使用: tryFuncs fs x = msum $ map ($ x) fs (最终,这个解决

如何使用。我希望具有类似的效果,但将函数列表作为参数:

tryFuncs :: [a -> Maybe b] -> a -> Maybe b
...
那么一个像这样的电话

tryFuncs [f, g, h] x
将成为可能,并按照

(f x) `mplus` (g x) `mplus` (h x)

如何实现这一点?

最简单的方法是将
msum
(mplus的列表版本)与
map
一起使用:

tryFuncs fs x = msum $ map ($ x) fs
(最终,这个解决方案将与厄尔詹·约翰森的答案相同,因为
可能
s
MonadPlus
相当于
第一个
的行为。但这是
a->b
Monoid的一个简洁的小应用,很容易被忽略。)

从概念上讲,您正在寻找的函数是<代码>mconcat

tryFuncs' :: Monoid b => [a -> Maybe b] -> a -> Maybe b
tryFuncs' = mconcat
不幸的是,
Maybe
的默认
Monoid
实例并不是您想要的(“忽略
无任何内容”
mappend
仅是
内容”),否则该解决方案会非常简洁

但是有一个
First
包装器围绕着
Maybe
提供了“retainfirst
Just
”行为,因此

-- newtype First a = First (Maybe a)
tryFuncsFirst :: [a -> First b] -> a -> First b
tryFuncsFirst = mconcat
剩下的是先将
包裹/展开到

firstify :: (a -> Maybe b) -> (a -> First b)
firstify f = First . f

firstifyList :: [a -> Maybe b] -> [a -> First b]
firstifyList = map firstify

getFirst :: First a -> Maybe a -- Defined in Data.Monoid
现在您可以通过包装mconcat UNWRAPING来恢复所需的功能

[a -> Maybe b] -> a -> Maybe b
tryFuncs fs x = getFirst (mconcat (firstifyList xs) x)
但是这是如何工作的呢?这里有两个幺半群在起作用,
第一个a
幺半群b=>(a->b)
,而后一个就是魔法发生的地方。要稍微解释一下实例,请使用
for
mappend

(a <> b) x = a x <> b c
-- and therefore
mconcat [a,b,c] x = mconcat [a x, b x, c x] -- (1)
(a b)x=a x b c
--因此
mconcat[a,b,c]x=mconcat[ax,bx,cx]--(1)
因此,现在可以理解上述代码:

  • First
    -包装所有输入函数,将它们从
    a->Maybe b
    带到
    a->First b
    ,这是相同的,但具有不同的
    Maybe
  • 实例

  • mconcat
    函数列表,它使用我刚才提到的
    monoidb=>(a->b)
    实例。创建的列表中的所有函数都应用于
    x
    ,留下一个
    第一个b
    的列表,然后再次连接,如(1)所示

  • 再次从
    第一个
    包装中提取得到的
    可能


  • @larsmans
    msum
    对空列表使用
    mzero
    ,因此这是不必要的。