警告:这是一个非常非标准的解决方案。但我个人非常喜欢它的优雅 - 以及潜在的思维弯曲。
在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])
所有这些函数都完全按照您从类型中假定的方式进行。 (但要注意的是,维基是一个有点过时了。现在,大部分的这些功能会自动为任何Foldable
类型的工作。)
您搜索可以从
swing mapMaybe :: [a -> Maybe b] -> a -> [b]
,然后申请启动该功能listToMaybe
。 (这两个函数都是从Data.Maybe
)
更一般的形式将(使用ClassyPrelude
在一些约束噪声的成本充分的通用性,是
swing mapM :: (Monad m, Traversable t) => t (a -> m b) -> a -> m (t b)
所以例如用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
是的,它可能把你的头变成糊状 - 但它像弯曲你的头看到一个笑脸,只与你的整个心灵。
'asum'在'Data.Foldable'的基础上。 – danidiaz
使用通用工具包中的['Star'](https://hackage.haskell.org/package/profunctors-5.2/docs/Data-Profunctor.html#t:Star),您还可以编写'runStar。 asum。 fmap Star',感谢'Alternative f => Alternative(Star f a)'实例。 – danidiaz
@danidiaz是的,我意识到几分钟前 - 我因为在Control.Applicative中寻找'asum'而被抛弃,其中定义了'Alternative'。这是一个巧妙的'星'的技巧!我一直在寻找像'星'这样的东西...... – Alec