Haskell sortBy
函数将(a -> a -> Ordering)
作为其第一个参数。任何人都可以教育我有什么推理吗?我的背景完全采用具有类似功能的语言而不是(a -> a -> Bool)
,因此必须编写一个返回LT
/ GT
的语言有点令人困惑。
这是使用静态类型/纯函数语言执行此操作的标准方法吗?这是ML下降语言特有的吗?是否有一些我没有看到的基本优势,或者使用布尔值隐藏 dis 优势?
汇总:
Ordering
不是GT | LT
,实际上是GT | EQ | LT
(显然GHC
为了排序而没有利用这个内容,但仍然)
更接近地回归三分法值来模拟两个元素比较的可能结果
在某些情况下,使用Ordering
而不是Bool
会保存比较
使用Ordering
可以更轻松地实施稳定排序
使用Ordering
向读者清楚地表明正在进行两个元素之间的比较(布尔值本身并不具备这个意义,尽管我感觉很多读者会认为它)< / p>
我暂时接受了Carl的回答,并发布了上述摘要,因为截至此编辑时,没有任何一个回答达到所有要点。
答案 0 :(得分:23)
我认为Boolean Blindness是主要原因。 Bool
是一种没有域语义的类型。在像sortBy
这样的函数的情况下,它的语义完全来自约定,而不是来自函数运行的域。
这为编写比较函数所涉及的心理过程增加了一个间接层。而不只是说“我可以返回的三个值小于,等于或大于”,排序的语义构建块,你说“我想要返回少于,所以我必须将它转换为布尔值”。还有一个额外的心理转换步骤始终存在。即使你精通大会,它仍会让你慢下来。如果你不熟悉惯例,你必须检查看它是什么,你会放慢脚步。
它是3值而不是2值这一事实意味着您不需要在排序实现中非常小心地获得稳定性 - 但这是一个次要的实现细节。这并不像实际让你的价值观具有意义那么重要。 (另外,Bool
并不比Ordering
更有效。它不是Haskell中的原语。它们都是库中定义的代数数据类型。)
答案 1 :(得分:20)
当你整理东西时,你把它们整理好;没有确定的“真实”价值。
更重要的是,“真实”意味着什么?第一个参数小于第二个?比...更棒?现在你要覆盖“真实”,真正意味着“小于”(或“大于”,取决于你选择如何实现这个功能)。如果他们是平等的呢?
那么,为什么不切断中间人,可以这么说,并返回你真正的意思?
答案 2 :(得分:11)
没有理由不能。如果您查看ghc implementation,它只会检查结果是否为GT
。代码的Haskell报告版本使用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 (<=)
通过了解元素何时EQ
,可以想象某些种类可以执行优化,但当前使用的实现不需要此信息。
答案 3 :(得分:6)
我认为有两个单独的设计决定:
1)创建Ordering
类型
2)选择sortBy
返回Ordering
值
Ordering
类型不仅仅适用于sortBy
- 例如,compare
是Ord
类型类的“核心”。它的类型是:: Ord a => a -> a -> Ordering
。给定两个值,然后,您可以发现它们是否小于,大于或等于任何其他比较函数((<)
,(<=)
,(>)
,{{ 1}}),你只能排除这三种可能性中的一种。
这是一个简单的例子,其中(>=)
(至少在我看来)使函数的意图更清晰一点:
Ordering
一旦你决定创建f a b =
case compare a b of
GT -> {- something -}
LT -> {- something -}
EQ -> {- something -}
类型,那么我认为在那些你正在寻找的信息(如Ordering
)的地方使用它是很自然的,而不是使用sortBy
作为一种解决方法。
答案 4 :(得分:6)
在我们确实需要区分Ordering
案例的情况下,保存比较需要三个值EQ
。在重复保留sort
或merge
时,我们会忽略EQ
个案,因此 谓词 less-then - 或等于语义是完全可以接受的。但不是union
或nubSort
我们确实希望区分三个比较结果。
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
用 lte 谓词编写后者是不自然的。