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

use*_*095 2 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)
Run Code Online (Sandbox Code Playgroud)

第二个是使用comparingfromData.Ord并给它一个函数,该函数将返回一个分数\ (x, y) -> (x, 1 / y),我认为这更具声明性,但需要更多的计算 ( 1 / y)

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

chi*_*chi 5

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

compareSol (s1, w1) (s2, w2) = compare (w1, sum s2) (w2, sum s1)
Run Code Online (Sandbox Code Playgroud)

以上等价于

compareSol (s1, w1) (s2, w2) 
   | w1 < w2   = LT
   | w1 > w2   = GT
   | otherwise = compare (sum s2) (sum s1)
Run Code Online (Sandbox Code Playgroud)

或者,完全展开,

compareSol (s1, w1) (s2, w2) 
   | w1 < w2 = LT
   | w1 > w2 = GT
   | sum s1 < sum s2 = GT
   | sum s1 > sum s2 = LT
   | otherwise = EQ
Run Code Online (Sandbox Code Playgroud)

随意交换比较,以实现您的目标。


Jon*_*rdy 5

您可以使用comparingDownData.Ord<>来自Data.Monoid

compareSol = comparing snd <> comparing (Down . sum . fst)
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您还可以使用更简单的flip代替Down

compareSol = comparing snd <> flip (comparing (sum . fst))
Run Code Online (Sandbox Code Playgroud)

这是几个功能的组合。

Data.Ord.comparing根据这些值的函数比较两个值 -comparing f等效于compare `on` f使用Data.Function.on.

comparing :: Ord a => (b -> a) -> b -> b -> Ordering
Run Code Online (Sandbox Code Playgroud)

Monoid实例为Ordering您提供字典顺序。

LT <> x = LT
GT <> x = GT
EQ <> x = x
Run Code Online (Sandbox Code Playgroud)

Monoid函数的实例允许您组合类型的比较函数a -> Ordering,或者在这种情况下a -> a -> Ordering

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
Run Code Online (Sandbox Code Playgroud)

最后,Downnewtype 反转它所包装的类型的顺序,为您提供免费的反向比较:

     0 <       1  ==  True
Down 0 <  Down 1  ==  False
     0 >       1  ==  False
Down 0 >  Down 1  ==  True
Run Code Online (Sandbox Code Playgroud)