如何应用在Haskell中工作的第一个部分函数?

时间:2016-08-16 21:29:15

标签: haskell

假设我有is_convertible_to_functionfns的部分函数列表a,我将其表示为ba的函数,我有类型为Maybe b的对象x。现在假设我要定义从aa的另一个函数,它取第Maybe bf x的值,如果这样Nothing存在于f,如果不存在fns则存在值Nothing。所以基本上它会为有效的第一个f输出f x,或者如果没有f则为Nothing

提出一些能够完成这项工作的代码并不难。例如,可以创建一个列表f从中删除所有[f x| f <- fns],然后取结果列表的头部,如果该列表为空,则为Nothing。但这感觉很笨拙,这似乎是一种普遍的情况,在Haskell中使用一些内置函数可以实现更加时尚的实现。如果是这样,那么我有兴趣知道它是什么。

3 个答案:

答案 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

是的,它可能会使你的头变得糊涂 - 但它只是弯着头看笑脸,只有全心全意。