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

时间:2017-01-21 15:22:59

标签: haskell monoids

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

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

但我无法弄清楚如何用两个变量函数做同样的事情。

这有效:

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

但它看起来像一个丑陋的解决方法。

有更好的方法吗?

2 个答案:

答案 0 :(得分:3)

这是自己写的代码 - 你只需要使类型连接起来。但是有一些标准工具(即ApplicativeTraversable)可以用来缩短代码。

Data.Traversable模块中sequenceA :: (Traversable t, Applicative f) => t (f a) -> f (t a)。如果专门针对[]的{​​{1}}实例以及函数应用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)]

我使用and代替f :: (Num n, Ord n) => n -> Bool f = and . sequenceA [(< 7), (> 7), (== 7)]

对于您的第二个功能,mconcat . map (All .)是正确的工具。我们必须将uncurry映射到二元函数列表上以获取元组的一元函数列表,以便我们可以使用uncurry将单个参数提升出来。因为sequenceA我们可以将其写为:

traverse f = sequenceA . map f

(注意,对于任何正确实现的g :: Ord n => n -> n -> Bool g = curry $ and . traverse uncurry [(<), (>), (==)] 实例,Ord>应该互斥。因此,这两个函数都将始终返回<。)

答案 1 :(得分:1)

原始代码的替代选择:

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

可以用无意义的方式进一步重写\f a b -> All (f a b)

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