Haskell:“groupBy”的令人惊讶的行为 [英] Haskell: surprising behavior of "groupBy"

查看:144
本文介绍了Haskell:“groupBy”的令人惊讶的行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图找出库函数groupBy(来自Data.List)的行为,它声称通过作为第一个参数传入的相等测试函数对列表元素进行分组。类型签名表明平等测试只需要类型

 (a  - > a  - > Bool)

但是,当我在GHCi 6.6中使用(&)作为相等测试时,结果不是我期望的:

  ghci> groupBy(<)[1,2,3,2,4,1,5,9] 
[[1,2,3,2,4],[1,5,9]]

相反,我希望运行严格增加的数字,如下所示:

  [[1,2,3],[2,4],[1,5,9]] 

我错过了什么?

解决方案

ghc 实现rel = noreferrer> groupBy

  groupBy ::(a  - > a  - > Bool) - > ; [a]  - > [(a)] 
groupBy _ [] = []
groupBy eq(x:xs)=(x:ys):groupBy eq zs
其中(ys,zs)= span eq x)xs

现在比较这两个输出:

 前奏列表> groupBy(<)[1,2,3,2,4,1,5,9] 
[[1,2,3,2,4],[1,5,9]]
前奏列表> groupBy(<)[8,2,3,2,4,1,5,9]
[[8],[2,3],[2,4],[1,5,9] ]

总之,会发生什么: groupBy 假定给定的函数(第一个参数)测试相等性,并因此假定比较函数是反射性传递性对称性 (请参阅等效关系)。这里的问题是小于关系不是自反的,也不是对称的。




编辑:以下实现仅假设传递性:

  groupBy'::(a  - > a - > Bool) - > [a]  - > [[a]] 
groupBy'_ [] = []
groupBy'_ [x] = [[x]]
groupBy'cmp(x:xs @(x':_ ))| cmp x x'=(x:y):ys
|否则= [x]:r
其中r @(y:ys)= groupBy'cmp xs


I'm trying to figure out the behavior of the library function groupBy (from Data.List), which purports to group elements of a list by an "equality test" function passed in as the first argument. The type signature suggests that the equality test just needs to have type

(a -> a -> Bool)

However, when I use (<) as the "equality test" in GHCi 6.6, the results are not what I expect:

ghci> groupBy (<) [1, 2, 3, 2, 4, 1, 5, 9]
[[1,2,3,2,4],[1,5,9]]

Instead I'd expect runs of strictly increasing numbers, like this:

[[1,2,3],[2,4],[1,5,9]]

What am I missing?

解决方案

Have a look at the ghc implementation of groupBy:

groupBy                 :: (a -> a -> Bool) -> [a] -> [[a]]
groupBy _  []           =  []
groupBy eq (x:xs)       =  (x:ys) : groupBy eq zs
                           where (ys,zs) = span (eq x) xs

Now compare these two outputs:

Prelude List> groupBy (<) [1, 2, 3, 2, 4, 1, 5, 9]
[[1,2,3,2,4],[1,5,9]]
Prelude List> groupBy (<) [8, 2, 3, 2, 4, 1, 5, 9]
[[8],[2,3],[2,4],[1,5,9]]

In short, what happens is this: groupBy assumes that the given function (the first argument) tests for equality, and thus assumes that the comparison function is reflexive, transitive and symmetric (see equivalence relation). The problem here is that the less-than relation is not reflexive, nor symmetric.


Edit: The following implementation only assumes transitivity:

groupBy' :: (a -> a -> Bool) -> [a] -> [[a]]
groupBy' _   []                        = []
groupBy' _   [x]                       = [[x]]
groupBy' cmp (x:xs@(x':_)) | cmp x x'  = (x:y):ys
                           | otherwise = [x]:r
  where r@(y:ys) = groupBy' cmp xs

这篇关于Haskell:“groupBy”的令人惊讶的行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆