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年增加的。
答案 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)
sortBy
将不会非常有意义:结果将取决于实现细节sortBy
,或者结果不会排序"正确(因为sortBy
被允许采取快捷方式假设传递性等。)