简体   繁体   English

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

[英]How do I apply the first partial function that works in Haskell?

Suppose I have a list fns of partial functions from a to b , which I represent as functions from a to Maybe b , and I have an object x of type a . 假设我有一个从ab的部分函数的列表fns ,我将其表示为从aMaybe b函数,并且我有一个类型为a的对象x Suppose now that I want to define another function from a to Maybe b which takes the value of the first fx that is not Nothing , if such an f exists in fns , or the value Nothing if no such f exists. 现在假设我想要定义另一个函数,从aMaybe b ,它取第一个fx的值不是Nothing ,如果这样的f存在于fns ,或者值Nothing如果不存在这样的f So basically it outputs fx for the first f that works, or Nothing if no f works. 所以基本上它输出fx的第f这样的作品,或者Nothing ,如果没有f工作。

It isn't hard to come up with some code that does the job. 提出一些能够完成这项工作的代码并不难。 For example, one can create a list [fx| f <- fns] 例如,可以创建一个列表[fx| f <- fns] [fx| f <- fns] remove all the Nothing s from it, and then take the head of the resulting list, or Nothing if that list is empty. [fx| f <- fns]从中删除所有Nothing ,然后取结果列表的头部,如果该列表为空,则为Nothing But that feels clumsy, and this seems like the kind of general situation for which there is a much more stylish implementation using some built-in function in Haskell. 但这感觉很笨拙,这似乎是一种普遍的情况,在Haskell中使用一些内置函数可以实现更加时尚的实现。 If so, then I'd be interested to know what it is. 如果是这样,那么我有兴趣知道它是什么。

This is what Alternative is for. 这就是Alternative的用途。 It represents choice and here you are choosing between Maybe values. 它代表选择,在这里你选择Maybe值。 You can do something like 你可以做点什么

foldr (<|>) empty [f x | f <- fns]

In Data.Foldable you also have asum :: (Foldable t, Alternative f) => t (fa) -> fa which does what you want even more directly: Data.Foldable你也有asum :: (Foldable t, Alternative f) => t (fa) -> fa它可以更直接地做你想要的:

asum [f x | f <- fns]

As a side remark, I should note that MonadPlus also does what you want for its Maybe instance. 作为旁注,我应该注意到MonadPlus也为它的Maybe实例做了你想要的。 As in the above, you can have 如上所述,你可以拥有

foldr mplus mempty [f x | f <- fns]

And

msum [f x | f <- fns]

But IMO you should use Alternative here since that more accurately conveys your meaning of "choice". 但IMO你应该在这里使用Alternative ,因为它更准确地传达了你的“选择”的含义。

In Data.Monoid , a newtype copy of Maybe , called First , has the "take the first Just " behaviour. Data.Monoid ,一个newtype的副本Maybe ,所谓的First ,有“拿第一Just ”行为。

If you were looking for a function of type 如果您正在寻找类型的功能

[a -> First b] -> a -> First b

with the behaviour you describe, it would simply be 根据你描述的行为,它就是这样

fold

from Data.Foldable , because the monoid behaviour for a -> does the pointwise lifting needed: the Monoid for a -> First b is exactly picking the first application outcome whic works. 来自Data.Foldable ,因为a ->的幺半群行为需要逐点提升:a的Monoid a -> First b正好选择了第一个应用结果。 Sadly (for my tears over this have been many), to get Maybe instead of First takes a little more work. 可悲的是(因为我的眼泪已经很多了),为了得到Maybe而不是First需要多做一些工作。

Note that the pointwise lifting, yanking a -> out through [] , is just the sort of job for sequenceA , so 注意,逐点提升,yanking a -> out through [] ,就是sequenceA的那种工作,所以

(asum .) . sequenceA

will do the job. 会做的。

It's good to get the monoid structure you need cued from the type: in this case, accessing the Alternative behaviour with asum will have to do. 从类型中获取需要提示的monoid结构是很好的:在这种情况下,使用asum访问Alternative行为必须这样做。

Warning: This is a really non-standard solution. 警告:这是一个非常非标准的解决方案。 But I personally really like it for its elegance - and the underlying mind-bending. 但我个人非常喜欢它的优雅 - 以及潜在的心灵弯曲。

On https://wiki.haskell.org/Pointfree you can find a function named swing . https://wiki.haskell.org/Pointfree上,您可以找到名为swing的函数。 Its implementation and type are confusing at first: 它的实现和类型最初令人困惑:

swing :: (((a -> b) -> b) -> c -> d) -> c -> a -> d
swing = flip . (. flip id)

You can get a first idea of what it does when you see its fully applied form: 当您看到完全应用的表单时,您可以首先了解它的作用:

swing f c a = f ($ a) c

In conjunction with other higher-order functions it does things that almost look like magic. 结合其他高阶函数,它可以完成看起来像魔术的事情。 Examples from the link: 链接示例:

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])

All these functions do exactly what you would assume from the types. 所有这些功能都完全按照您所假设的类型执行。 (But note that the wiki is a little out of date. By now, most of these functions automatically work for any Foldable type.) (但请注意,wiki有点过时。到目前为止,大多数这些功能都可以自动适用于任何Foldable类型。)

The function that you search could start from 您搜索的功能可以从中开始

swing mapMaybe :: [a -> Maybe b] -> a -> [b]

and then apply listToMaybe . 然后应用listToMaybe (Both functions are from Data.Maybe ) (这两个函数都来自Data.Maybe

A more general form would be 更一般的形式是

swing mapM :: (Monad m, Traversable t) => t (a -> m b) -> a -> m (t b)

so for example (using the ClassyPrelude for full generality at the cost of some constraint noise, with headMay as a more general form of listToMaybe ): 因此,例如(使用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

Yes, it might turn your head into mush - but it's like bending your head to see a smiley, only with your whole mind. 是的,它可能会让你的头变得糊涂 - 但这就像弯曲你的头看到一个笑脸,只有你的整个头脑。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM