在haskell中是否有一种方法可以通过多个参数和不同的顺序进行紧凑和有效的比较

时间:2017-04-01 09:29:16

标签: haskell compare

假设我们有一个元组列表,我们需要在某个标准上找到最大值。标准如下 - 最重要的是元组的第一个元素(越多越好)不太重要的是第二个元素(越少越好)。

我知道在Haskell中表达这两种方式。

首先是创建一个能够进行所有比较并返回(EQ, LT, GT)

的函数
compareSol (s1, w1) (s2, w2) = if weightComp == EQ then sizeComp else weightComp where 
    weightComp = compare w1 w2
    sizeComp = compare (Map.foldl' (+) 0  s2) (Map.foldl' (+) 0  s1)

第二个是使用来自comparing的{​​{1}}并为其提供一个返回得分Data.Ord的函数。我认为这更具说明性,但需要更多计算({{ 1}})

有没有办法以声明和有效的方式表达这一点,比如sql?

2 个答案:

答案 0 :(得分:4)

您可以使用comparing中的DownData.Ord与来自<>的{​​{1}}使用{/ 1}}:

Data.Monoid

在这种情况下,您还可以使用更简单的compareSol = comparing snd <> comparing (Down . sum . fst) 代替flip

Down

这是一些功能的组合。

compareSol = comparing snd <> flip (comparing (sum . fst)) 根据这些值的函数比较两个值 - 使用Data.Ord.comparing comparing f相当于compare `on` f

Data.Function.on

comparing :: Ord a => (b -> a) -> b -> b -> Ordering 的{​​{1}}实例为您提供词典排序。

Monoid

函数的Ordering实例允许您组合LT <> x = LT GT <> x = GT EQ <> x = x 类型的比较函数,或者在这种情况下Monoid

a -> Ordering

最后,a -> a -> Ordering newtype反转了它所包含类型的顺序,为你提供了免费的反向比较:

instance Monoid b => Monoid (a -> b)
-- instance Monoid c => Monoid (a -> b -> c)
-- instance Monoid Ordering
-- instance Monoid (a -> b -> Ordering)
-- instance Monoid (a -> a -> Ordering)  given  a ~ b

答案 1 :(得分:2)

我无法理解您想要的精确排序,但可能以下是您正在寻找的一些变体

compareSol (s1, w1) (s2, w2) = compare (w1, sum s2) (w2, sum s1)

以上相当于

compareSol (s1, w1) (s2, w2) 
   | w1 < w2   = LT
   | w1 > w2   = GT
   | otherwise = compare (sum s2) (sum s1)

或者,完全展开,

compareSol (s1, w1) (s2, w2) 
   | w1 < w2 = LT
   | w1 > w2 = GT
   | sum s1 < sum s2 = GT
   | sum s1 > sum s2 = LT
   | otherwise = EQ

随意交换比较,以达到目标。