将布尔函数列表应用于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实例,><应该是互斥的。因此,这两个函数都将始终返回False。)

原始代码的一个替代方案:

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

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

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

最新更新