假设我们有一个元组列表,我们需要在某个标准上找到最大值。标准如下 - 最重要的是元组的第一个元素(越多越好)不太重要的是第二个元素(越少越好)。
我知道在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?
答案 0 :(得分:4)
您可以使用comparing
中的Down
和Data.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
随意交换比较,以达到目标。