假设我们有一个元组列表,我们需要在某个标准上找到最大值。标准如下 - 最重要的是元组的第一个元素(越多越好)不太重要的是第二个元素(越少越好)。
我知道在 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?
我无法理解您想要的确切顺序,但您可能正在寻找以下的一些变体
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)
随意交换比较,以实现您的目标。
您可以使用comparing并Down从Data.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)
| 归档时间: |
|
| 查看次数: |
777 次 |
| 最近记录: |