根据值 (a, b) 的差异对 Int 对列表进行排序

Sort a list of Int pairs by the difference of the values (a, b)

如何根据值 |first - second| 的差值按升序对 listInt 对进行排序?

为了计算差异我写了这段代码:

ab :: (Int, Int) -> Int
ab (x, y) = if x - y >= 0 then (x - y)
            else (x - y) * (-1)

我想对我得到的值使用 quicksort

sort :: [(Int,Int)] -> [(Int,Int)]
sort [] = []
sort (x:xs) = sort smallerOrEqual ++ [x] ++ sort larger
          where smallerOrEqual = [a | a <- xs, a <= x]
                larger = [a | a <- xs, a > x]

问题是如何将 ab 函数构建到 the 排序函数中?我尝试了几种方法,但总是出现编译错误。

让我们只使用标准库函数!

首先,有一个通用版本的排序函数,名为 sortBy(我将使用 GHCi 出色的 :t 命令展示相关函数的类型):

ghci> import Data.List
ghci> :t sortBy
sortBy :: (a -> a -> Ordering) -> [a] -> [a]

sortBy 的第一个参数表明,为了比较元素,我们需要一个 排序谓词 — 一个函数,它接受列表的两个元素并判断第一个元素是否是更大。在许多情况下,包括您的情况,您不必自己定义这样的函数。相反,您可以使用“测量”列表元素的重要性的函数。例如。你有一个列表元素 (x,y) 并且它的度量是 |x-y| — 这正是你的 ab 函数,但请记住我们希望它通过标准的定义。

现在,我们有两个任务:1)定义(Int, Int) -> Int类型的度量函数; 2) 学习如何把它变成一个排序谓词。我告诉过后者是微不足道的,因为它可以通过标准函数 comparing:

完成
ghci> import Data.Ord
ghci> :t comparing
comparing :: Ord a => (b -> a) -> b -> b -> Ordering

所以我的建议是 comparing absortBy 的第一个参数的完美匹配。让我们转向另一个任务:通过标准函数定义 ab

考虑 - 函数的类型:

ghci> :t (-)
(-) :: Num a => a -> a -> a

如果用 Int 代替 a(¹),您几乎可以得到想要的类型,即 Int -> Int -> Int。在这里,我们遇到了非常频繁的任务,即将一个函数从两个参数 ((-)) 转换为作用于对的函数。幸运的是,有一个标准函数可以做到这一点,即 uncurry:

ghci> :t uncurry (-)
uncurry (-) :: Num c => (c, c) -> c

这就是我们需要的!现在我们只需将它与计算 |·|abs 函数进行管道传输,我们就很好了。我们将函数组合成 . 的方法。结果解决方案是这个:

import Data.List (sortBy)
import Data.Ord  (comparing)

sortAbsPairs :: [(Int,Int)] -> [(Int,Int)]
sortAbsPairs = sortBy (comparing $ abs . uncurry (-))

假设您将其保存在 sort.hs 中,您可以在 GHCi 中试用它:

ghci>:l sort.hs
Ok, one module loaded.
ghci> sortAbsPairs [(8,20), (5, 10), (1,2)]
    [(1, 2), (5, 10), (8, 20)]

(¹) 您实际上可以要求 GHCi 通过设置名为 TypeApplications:

的语言扩展来用类型替换函数的类型参数
ghci> :set -XTypeApplications
ghci> :t (-) @Int
(-) @Int :: Int -> Int -> Int

sortBy虽广为人知,但大多伴随着comparing。您可以改用 sortOnsortOn 的优点是它使用了 Schwartzian 变换,即它只为每个元素计算一次差异。

--Prelude Data.List> :t sortOn
--sortOn :: Ord b => (a -> b) -> [a] -> [a]

import Data.List(sortOn)
sort = sortOn (abs . uncurry (-))

但是如果你真的想使用你原来的排序,模式匹配对:

sort ((x,x'):xs) = [ (a,a') | (a,a') <- xs, -- ... your homework here

我稍后会扩展作业部分以使其成为完整答案。