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

Apply a list of Boolean functions to two arguments in Haskell

我有一个 a -> b -> Bool 类型的函数列表,我正在尝试将它们应用于两个输入并将结果与​​ AllAny 组合。我有这个与一个变量的函数一起工作:

mconcat (map (All . ) [(<7),(>7),(==7)]) $ 6

但我不知道如何对两个可变函数执行相同的操作。

这个有效:

mconcat (map (All . ) (map (uncurry) [(<),(>),(==)])) $ (,) 6 7

但在我看来这是一个丑陋的解决方法。

有更好的方法吗?

这是一种自行编写的代码 - 您只需将类型连接起来即可。但是有一些标准工具(即 ApplicativeTraversable)可以用来缩短代码。

Data.Traversable 模块中生活 sequenceA :: (Traversable t, Applicative f) => t (f a) -> f (t a)。当专用于 []Traversable 实例和应用函数 (->) r 时,我们得到:

sequenceA :: [r -> a] -> r -> [a]

因此 sequenceA[] 中抽取 ->,将列表中的每个函数应用于固定参数。

sequenceA [(< 7), (> 7), (== 7)] :: (Num n, Ord n) => n -> [Bool]
-- equivalent to:
\n -> map ($ n) [(< 7), (> 7), (== 7)]

所以你的第一个函数可以写成

f :: (Num n, Ord n) => n -> Bool
f = and . sequenceA [(< 7), (> 7), (== 7)]

我正在使用 and 而不是 mconcat . map (All .)

对于您的第二个功能,uncurry 是正确的工具。我们必须将 uncurry 映射到二进制函数列表上以获得元组的一元函数列表,以便我们可以使用 sequenceA 提升单个参数。因为traverse f = sequenceA . map f我们可以写成:

g :: Ord n => n -> n -> Bool
g = curry $ and . traverse uncurry [(<), (>), (==)]

(注意,对于 Ord 的任何 correctly-implemented 实例,>< 应该是互斥的。所以这两个函数总是 return False.)

原始代码的接近替代:

mconcat (map (\f a b -> All (f a b)) [(<),(<=)]) 3 4

可以进一步以毫无意义的风格重写 \f a b -> All (f a b)

mconcat (map ((.) (All .)) [(<),(<=)]) 3 4