为什么sortBy如此奇怪地不受约束,为什么没有一般的排序

时间:2016-06-08 01:28:23

标签: sorting haskell

http://zvon.org/other/haskell/Outputlist/sortBy_f.html处的示例2定义了比较函数xxx a b = if (odd a) then LT else GT。 Haskell似乎对此作为比较函数感到满意,但我不理解"比较"在这种情况下。什么是允许这样的东西的应用程序? (这里,2> 4和4> 2。)

作为参考,请考虑Python和Mathematica方法:列表基于单变量"键"将列表项映射到已订购的项的函数。这看起来非常明智。 (实际上,Python将类似Haskell的比较排序为多余的,并用排序键替换它们。)Haskell(显然)对此进行判断的基础是什么?是否有任何关于提供sortOn功能的讨论,以鼓励更加一致的(?)概念"比较"。 (我认识到" key"函数可用于比较函数或使数据类型被排序为Ord的实例,但这只是感觉不必要的尴尬和间接的东西所以简单。)

我错过了什么?这只是遗留问题,就像Python丢弃的那样,还是存在这种情况的数学动机?

编辑:正如Nouri所述,Data.List.sortOn确实存在于列表中。这显然是在2014年增加的。

5 个答案:

答案 0 :(得分:6)

sortBy基本上以相同的方式不受约束,并且基本上相同的原因,Ord实例通常不受约束。 Haskell不依赖于键入。在Haskell中,您根本无法陈述或证明某个关系实际上是一个总排序。在像Agda这样的语言中,sortBy可以证明排序确实是一个,并产生证明结果确实是输入的排序排列。这不容易! Python方法似乎在没有得到任何保证的情况下失去了一些灵活性,因此它并不像解决方案那样闻起来。

答案 1 :(得分:2)

根据元素的函数对某些有序类型进行排序很容易用sortBy和标准on函数表示(我相信这主要存在于这个精确的用例中):

import Data.Function (on)
import Data.List (sortBy)

-- | Sort in the Python/Mathematica way the question describes.
sortOn :: Ord key => (a -> key) -> [a] -> [a]
sortOn f = sortBy (compare `on` f)

-- Code example
type Person = String
type Age = Int    

example :: [(Person, Age)]
example = sortOn snd input
    where input = [ ("Mary", 33)
                  , ("Mario", 12)
                  , ("Mariama", 25)
                  , ("Mariano", 58)
                  ]

有些人可能会在这里提到密钥提取函数没有被记忆 - 它将在相同的参数上反复调用(比如N log N调用,我下注)。但这也很容易解决:

sortOn :: Ord key => (a -> key) -> [a] -> [a]
sortOn f = map fst 
         . sortBy (compare `on` snd) 
         . map (\a -> (a, f a))

还有第三个因素可以覆盖几个评论者提出的性能问题:如果排序确实是关键的性能瓶颈,那么也许一个人不应该在第一个使用Haskell的列表类型地点! vector-algorithms包在可变Vector上提供了几种排序算法。他们确实使用了这里讨论的e -> e -> Ordering界面,但如果重要的话,这应该很容易解决。

TL; DR: Meh。

答案 2 :(得分:1)

  

允许这些事情的应用是什么?

取决于您正在解决的问题域。当你执行sortBy xxx [1,2,3,4,5,6,7]时,它只是做它应该做的事情。 sortBy是一个接受(a -> a -> Ordering)类型函数的函数。因此,您可以传递满足该类型签名的任何函数。 Haskell没有,也不应该限制它!

  

作为参考,请考虑Python和Mathematica方法:列表基于单变量"键"将列表项映射到已订购的项的函数。

不是Python专家,但即使使用Python 3,我也可以使用它:

>>> x = [1,2,3,4,5]
>>> x.sort(key=lambda x: x % 2 == 0)
>>> x
[1, 3, 5, 2, 4]
  

这只是一个传统,就像Python丢弃的那样,或者是否存在这种情况的数学动机?

不,这不是遗产。这就是它应该如何运作的方式。 :)

答案 3 :(得分:1)

成对比较具有一些优点,例如,如果您稍微更改比较函数以在均匀之前对赔率进行排序,但按其自然顺序排序,例如

xxx a b | both odd || both even = compare a b
        | odd a && even b = LT
        | otherwise = GT
       where both f = f a && f b

> sortBy xxx [1..6]
[1,3,5,2,4,6]

答案 4 :(得分:0)

如果您传递给它的函数没有定义某种ordering,那么

sortBy将不会非常有意义:结果将取决于实现细节sortBy,或者结果不会排序"正确(因为sortBy被允许采取快捷方式假设传递性等。)