Data.List中nubBy的实现不一致?

时间:2014-03-29 21:01:01

标签: haskell ghc

我正在浏览Data.List中的nubBy函数的源代码:

nubBy                   :: (a -> a -> Bool) -> [a] -> [a]
#ifdef USE_REPORT_PRELUDE
nubBy eq []             =  []
nubBy eq (x:xs)         =  x : nubBy eq (filter (\ y -> not (eq x y)) xs)
#else
nubBy eq l              = nubBy' l []
  where
    nubBy' [] _         = []
    nubBy' (y:ys) xs
       | elem_by eq y xs = nubBy' ys xs
       | otherwise       = y : nubBy' ys (y:xs)

现在在我看来,上面的两个版本彼此不同。 如果我使用USE_REPORT_PRELUDE版本,我会

nubBy (>) [1..10]
[1,2,3,4,5,6,7,8,9,10]

而另一个实现产生

nubBy (>) [1..10]
[1]

这背后的原因是什么?

2 个答案:

答案 0 :(得分:14)

我认为nubBy要求二进制布尔运算是等价关系。

这与sortBy的精神大致相同,需要预先排序关系(反身和传递)。如果此要求无效,则quicksort和mergesort将成为非等效算法。 Haskell报告的目的是允许实现使用它们中的任何一个(或其他正确的排序算法)。

类似地,如果允许nubBy比较是非等价的,则实施被不必要地限制为精确使用引用Prelude算法,从而阻止使用更有效的替代方法。


老实说,对运营商的确切要求传递给了" ... By"并不总是显而易见的。 例如,sortBy的文档似乎只保证对总排序的正确性,虽然我期望实际的实现也适用于更大类的排序,只要结果被解释为由排序引起的等价。

nubBy的文档只是声明第一个参数是"用户提供的等式谓词"。因此,它只能保证平等,而不是任意等价。

但是,我的感觉是,如果它的实现适用于相等,那么 也可以用于等价(当然,只要读取结果)。这可能通过利用" free theorem"与nubBy类型相关联。我缺乏参数化方面的专业知识背叛了我:)

答案 1 :(得分:3)

a GHC bug report这个。 nubBy的行为最初与Prelude实施相匹配,但在某些时候被更改为another bug report的“修复”。我认为陪审团仍然没有做正确的事情。

您可以在codepad.org上看到,您的代码确实产生了[1,2,3,4,5,6,7,8,9,10];但是在ideone.com上,您的代码会生成[1]。很明显,人们使用较旧的或不同的实现。