假设我有is_convertible_to_function
到fns
的部分函数列表a
,我将其表示为b
到a
的函数,我有类型为Maybe b
的对象x
。现在假设我要定义从a
到a
的另一个函数,它取第Maybe b
个f x
的值,如果这样Nothing
存在于f
,如果不存在fns
则存在值Nothing
。所以基本上它会为有效的第一个f
输出f x
,或者如果没有f
则为Nothing
。
提出一些能够完成这项工作的代码并不难。例如,可以创建一个列表f
从中删除所有[f x| f <- fns]
,然后取结果列表的头部,如果该列表为空,则为Nothing
。但这感觉很笨拙,这似乎是一种普遍的情况,在Haskell中使用一些内置函数可以实现更加时尚的实现。如果是这样,那么我有兴趣知道它是什么。
答案 0 :(得分:12)
这是Alternative
的用途。它代表选择,您在此处选择Maybe
值。你可以做点什么
foldr (<|>) empty [f x | f <- fns]
在Data.Foldable
中,您还有asum :: (Foldable t, Alternative f) => t (f a) -> f a
可以直接执行您想要的操作:
asum [f x | f <- fns]
作为旁注,我应该注意MonadPlus
也为Maybe
实例做了你想做的事。如上所述,你可以拥有
foldr mplus mempty [f x | f <- fns]
和
msum [f x | f <- fns]
但IMO你应该在这里使用Alternative
,因为这更准确地表达了你对“选择”的意思。
答案 1 :(得分:9)
在Data.Monoid
中,名为newtype
的{{1}} Maybe
副本具有“采取第一个First
”行为。
如果您正在寻找类型
的功能Just
根据您描述的行为,它只是
[a -> First b] -> a -> First b
来自fold
的,因为Data.Foldable
的幺半群行为需要逐点提升:a ->
Monoid
正在挑选第一个有效的应用结果。可悲的是(因为我的眼泪已经很多),要获得a -> First b
而不是Maybe
需要更多的工作。
请注意,从First
开始逐点提升{yanking a ->
只是[]
的工作,所以
sequenceA
将完成这项工作。
从类型中获取需要提示的monoid结构是很好的:在这种情况下,使用(asum .) . sequenceA
访问Alternative
行为必须这样做。
答案 2 :(得分:4)
警告:这是一个非常非标准的解决方案。但我个人非常喜欢它的优雅 - 以及潜在的心灵弯曲。
在https://wiki.haskell.org/Pointfree上,您可以找到名为swing
的函数。它的实现和类型最初令人困惑:
swing :: (((a -> b) -> b) -> c -> d) -> c -> a -> d
swing = flip . (. flip id)
当您看到完全应用的表单时,您可以首先了解它的作用:
swing f c a = f ($ a) c
与其他高阶函数一起,它可以完成几乎看起来像魔法的事情。链接示例:
swing map :: [a -> b] -> a -> [b]
swing any :: [a -> Bool] -> a -> Bool
swing foldr :: b -> a -> [a -> b -> b] -> b
swing zipWith :: [a -> b -> c] -> a -> [b] -> [c]
swing find :: [a -> Bool] -> a -> Maybe (a -> Bool)
swing partition :: [a -> Bool] -> a -> ([a -> Bool], [a -> Bool])
所有这些功能都完全符合您对类型的假设。 (但请注意,wiki有点过时。到目前为止,大多数这些函数自动适用于任何Foldable
类型。)
您搜索的功能可以从
开始swing mapMaybe :: [a -> Maybe b] -> a -> [b]
然后应用listToMaybe
。 (两个函数都来自Data.Maybe
)
更通用的形式是
swing mapM :: (Monad m, Traversable t) => t (a -> m b) -> a -> m (t b)
所以例如(使用ClassyPrelude
以一些约束噪声为代价获得完全的一般性,headMay
作为listToMaybe
的更一般形式:
f :: (Traversable t, MonoFoldable (t b), Element (t b) ~ b)
=> t (a -> Maybe b) -> a -> Maybe b
f functions x = join $ headMay <$> swing mapM functions x
是的,它可能会使你的头变得糊涂 - 但它只是弯着头看笑脸,只有全心全意。