简体   繁体   English

将布尔函数列表应用于Haskell中的两个参数

[英]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的函数列表,并且正在尝试将它们应用于两个输入并将结果与AllAny 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. 但是您可以使用一些标准工具(即ApplicativeTraversable )来缩短代码。

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.

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