考虑以下 Haskell 代码:
countWhere :: (a -> Bool) -> [a] -> Int
countWhere predicate xs = length . filter predicate $ xs
在 JavaScript 中,这将被写成如下:
function countWhere(predicate, xs) {
return xs.filter(predicate).length;
}
如您所见,函数组合与 JavaScript 中的链接方法非常相似。我真的很喜欢链接方法从左到右读取的方式。在 Haskell 中,我可以使用>>>
fromControl.Arrow
和 reverse 函数应用程序执行类似的操作,如下所示:
import Control.Arrow
($>) :: a -> (a -> b) -> b
($>) = flip ($)
countWhere :: (a -> Bool) -> [a] -> Int
countWhere predicate xs = xs $> filter predicate >>> length
现在我想以无点风格编写这个函数。使用函数组合我会写如下:
(.:) :: (b -> c) -> (d -> a -> b) -> d -> a -> c
(.:) = (.) (.) (.)
countWhere :: (a -> Bool) -> [a] -> Int
countWhere = length .: filter
但是,我想使用反向函数组合以无点样式编写此函数,如下所示:
(.:) :: (b -> c) -> (d -> a -> b) -> d -> a -> c
(.:) = (.) (.) (.)
(:.) :: (d -> a -> b) -> (b -> c) -> d -> a -> c
(:.) = flip (.:)
countWhere :: (a -> Bool) -> [a] -> Int
countWhere = filter :. length
我的抱怨是我必须:.
根据函数组合而不是反向函数组合来定义函数。那是:
(:.) = flip $ (.) (.) (.)
-- instead of
(:.) = (>>>) (>>>) (>>>)
当然(>>>) (>>>) (>>>)
是错误的类型。这不是我正在寻找的功能。
函数组合的美妙之处在于它可以与自身组合形成“高阶函数组合”,如上所示。因此,尽管它的类型签名直观地是向后的,但它实际上是向前的,这就解释了为什么f . g = \x -> f (g x)
而不是f . g = \x -> g (f x)
.
这让我想到了我的实际问题:有没有办法根据反向函数组合(即)定义“高阶反向函数组合”>>>
而不是flip
相应的“高阶函数组合”?
我正在寻找一个源于范畴论或其他数学分支的答案。