为什么不排序(a - > a - > Bool)?

Ina*_*thi 20 sorting haskell

Haskell sortBy函数(a -> a -> Ordering)作为其第一个参数.任何人都可以教育我有什么推理吗?我的背景完全是在具有类似功能的语言中(a -> a -> Bool)取而代之,因此必须编写一个返回LT/ GT有点令人困惑的语言.

这是在静态类型/纯函数语言中执行此操作的标准方法吗?这是ML下降语言特有的吗?是否有它的一些基本的优点是,我没有看到,或者一些隐藏的DIS优势,使用布尔值呢?


总结:

  • 一个Ordering不是GT | LT,它实际上GT | EQ | LT(显然GHC没有在引擎盖下使用它来进行分类,但仍然)

  • 返回三分法值更接近地模拟两个元素的比较的可能结果

  • 在某些情况下,使用Ordering而不是Bool将保存比较

  • 使用an Ordering可以更容易地实现稳定的排序

  • 使用a Ordering使读者清楚地知道两个元素之间正在进行比较(布尔值本身并不具备这个含义,尽管我感觉很多读者都会认为它)

我暂时接受了卡尔的回答,并发布了上述摘要,因为在此编辑中没有一个答案达到了所有要点.

Car*_*arl 23

我认为布尔盲症是主要原因.Bool是一种没有域语义的类型.它的语义在函数的情况下sortBy完全来自约定,而不是来自函数所在的域.

这为编写比较函数所涉及的心理过程增加了一个间接层次.而不只是说"我可以返回的三个值小于,等于或大于",排序的语义构建块,你说"我想要返回少于,所以我必须将它转换为布尔值".还有一个永远存在的额外心理转换步骤.即使你精通大会,它仍会让你慢下来.如果你不熟悉这个惯例,那么你必须检查一下它是什么,你会慢下来.

事实上,它是3值而不是2值意味着您不需要在排序实现中非常小心地获得稳定性 - 但这是一个次要的实现细节.这并不像实际让你的价值观具有意义那么重要.(而且,Bool效率不高Ordering.它不是Haskell中的原语.它们都是库中定义的代数数据类型.)


mip*_*adi 20

当你对东西进行分类时,你要把它们整理好; 没有确定的"真相"价值.

更重要的是,"真实"意味着什么?第一个参数小于第二个?比...更棒?现在你要覆盖"真实",真正意味着"小于"(或"大于",取决于你选择如何实现这个功能).如果他们是平等的呢?

那么,为什么不切出的中间人,可以这么说,并返回你真正的意思吗?

  • @Inaimathi:在Haskell中,声明像"Ordering"这样适合你的问题的数据类型既简单又便宜.在所有其他语言中情况并非如此,因此您会看到很多人将圆柱体粘在圆孔中.在Haskell中不需要像这样丢失信息(代表`LT`,`GT`,`EQ`作为`Bool`),所以我们不这样做.此外,"Bool"对上下文非常敏感."订购"不是. (9认同)
  • "为什么不切断中间人......"我不知道.为什么不?这几乎是我的问题.正如我所指出的,Haskell是我用过的第一种用这种方式表达的语言,所以我想知道它的基本原理是什么,以及为什么世界上大部分人似乎都采用不同的方式.我完全可以接受这可能是正确的方式©™,但我想知道为什么会这样. (4认同)
  • 有序集合是指具有单个反身,反对称,传递关系的集合,称为"小于或等于"; 关系自然由布尔值函数表示. (3认同)

Dan*_*ton 11

没有理由不能.如果你看一下ghc实现,它只检查结果是否GT存在.代码的Haskell Report版本使用insertBy,它同样只检查GT或不检查.您可以编写以下内容并使用它而不会出现任何问题:

sortByBool :: (a -> a -> Bool) -> [a] -> [a]
sortByBool lte = sortBy (\x y -> if lte x y then LT else GT)

sort' :: Ord a => [a] -> [a]
sort' = sortByBool (<=)
Run Code Online (Sandbox Code Playgroud)

有些种类可以通过了解元素何时进行优化EQ,但当前使用的实现不需要此信息.


ami*_*dfv 6

我认为有两个独立的设计决策:
1)创建Ordering类型
2)选择sortBy返回Ordering

Ordering类型不仅仅是有用的sortBy- 例如,compareOrd类型类的"核心" .它的类型是:: Ord a => a -> a -> Ordering.给定两个值,那么,你可以找出他们是否是小于,大于或等于-与任何其他比较函数((<),(<=),(>),(>=))你只能排除那些三种可能性之一.

这是一个简单的例子,其中Ordering(至少在我看来)使函数的意图更清晰一些:

f a b = 
  case compare a b of
    GT -> {- something -}
    LT -> {- something -}
    EQ -> {- something -}
Run Code Online (Sandbox Code Playgroud)

一旦你决定创建这个Ordering类型,那么我认为在那些你正在寻找的信息(如sortBy)中使用它是很自然的,而不是Bool用作一种变通方法.


Wil*_*ess 6

在我们需要区分案例的情况下,Ordering需要三个值来保存比较EQ.在重复保留中,sort或者merge我们忽略了这种EQ情况,因此具有较少或等于语义的谓词是完全可以接受的.但不是在的情况下,或者是我们期望区分3个比较的结果.unionnubSort

mergeBy lte (x:xs) (y:ys)
    | lte y x   = y : mergeBy lte (x:xs) ys
    | otherwise = x : mergeBy lte xs (y:ys)

union (x:xs) (y:ys) = case compare x y of 
    LT -> x : union  xs (y:ys) 
    EQ -> x : union  xs    ys 
    GT -> y : union (x:xs) ys
Run Code Online (Sandbox Code Playgroud)

lte谓词编写后者是不自然的.