[英]Apply a list of Boolean functions to two arguments in Haskell
I have a list of functions of type a -> b -> Bool
, and am trying to apply them to two inputs and combine the results with All
or Any
. 我有一个类型a -> b -> Bool
的函数列表,并且正在尝试将它们应用于两个输入并将结果与All
或Any
。 I have this working with functions of one variable: 我使用一个变量的函数来工作:
mconcat (map (All . ) [(<7),(>7),(==7)]) $ 6
but I cannot figure out how to do the same with two variable functions. 但我不知道如何使用两个变量函数来执行相同的操作。
This works: 这有效:
mconcat (map (All . ) (map (uncurry) [(<),(>),(==)])) $ (,) 6 7
but it looks to me like an ugly workaround. 但在我看来,这是一个丑陋的解决方法。
Is there a better way to do this? 有一个更好的方法吗?
This is the sort of code that writes itself - you just have to make the types join up. 这是一种自我编写的代码-您只需要使类型联接即可。 But there are a couple of standard tools (namely Applicative
and Traversable
) which you can use to make your code shorter. 但是您可以使用一些标准工具(即Applicative
和Traversable
)来缩短代码。
In the Data.Traversable
module lives sequenceA :: (Traversable t, Applicative f) => t (fa) -> f (ta)
. 在Data.Traversable
模块中,存在着sequenceA :: (Traversable t, Applicative f) => t (fa) -> f (ta)
。 When specialised to []
's instance of Traversable
and the function applicative (->) r
we get: 当专门研究[]
的Traversable
实例和函数应用(->) r
我们得到:
sequenceA :: [r -> a] -> r -> [a]
So sequenceA
yanks ->
out of []
, applying each function in the list to a fixed argument. 因此, sequenceA
从[]
移出->
,将列表中的每个函数应用于固定参数。
sequenceA [(< 7), (> 7), (== 7)] :: (Num n, Ord n) => n -> [Bool]
-- equivalent to:
\n -> map ($ n) [(< 7), (> 7), (== 7)]
So your first function can be written as 所以你的第一个函数可以写成
f :: (Num n, Ord n) => n -> Bool
f = and . sequenceA [(< 7), (> 7), (== 7)]
I'm using and
instead of mconcat . map (All .)
我正在使用and
不是mconcat . map (All .)
mconcat . map (All .)
. mconcat . map (All .)
。
For your second function, uncurry
is the right tool. 对于第二项功能, uncurry
是正确的工具。 We have to map uncurry
over the list of binary functions to get a list of unary functions of tuples, so that we can hoist the single argument out using sequenceA
. 我们必须在二进制函数列表上映射uncurry
以获得元组的一元函数列表,以便可以使用sequenceA
提升单个参数。 Because traverse f = sequenceA . map f
因为traverse f = sequenceA . map f
traverse f = sequenceA . map f
we can write it as: traverse f = sequenceA . map f
我们可以写成:
g :: Ord n => n -> n -> Bool
g = curry $ and . traverse uncurry [(<), (>), (==)]
(NB, for any correctly-implemented instance of Ord
, >
and <
should be mutually exclusive. So both of these functions will always return False
.) (注意,对于Ord
任何正确实现的实例, >
和<
应该是互斥的。因此,这两个函数将始终返回False
。)
A close alternative to the original code: 原始代码的替代方案:
mconcat (map (\f a b -> All (f a b)) [(<),(<=)]) 3 4
One can further rewrite \\fab -> All (fab)
in pointless style: 可以用无意义的方式进一步重写\\fab -> All (fab)
:
mconcat (map ((.) (All .)) [(<),(<=)]) 3 4
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.