我想知道为什么下面的调用groupBy
不起作用:我的谓词是x < y
,所以我希望[1, 6]
是一个组,但相反,Haskell 放入[1, 6, 4, 2]
了一个组。
Prelude Data.List> groupBy (\x y -> x < y) [8,5,3,2,1,6,4,2]
[[8],[5],[3],[2],[1,6,4,2]]
Run Code Online (Sandbox Code Playgroud)
更奇怪的是,当我将最后一个数字更改为 -2 时,我期望的行为与上述示例中的行为相同。也就是说,因为 2 和 -2 都小于 4,所以我希望结果中[1, 6, 4, -2]
会组成一个组。但是,这一次,Haskell 将 -2 放在了一个组中。
Prelude Data.List> groupBy (\x y -> x < y) [8,5,3,2,1,6,4,-2]
[[8],[5],[3],[2],[1,6,4],[-2]]
Run Code Online (Sandbox Code Playgroud)
我对 的理解有误groupBy
吗?
在 的实现中groupBy
,x
始终是子列表的第一项。实际上,groupBy
实现为:
Run Code Online (Sandbox Code Playgroud)groupBy :: (a -> a -> Bool) -> [a] -> [[a]] groupBy _ [] = [] groupBy eq (x:xs) = (x:ys) : groupBy eq zs where (ys,zs) = span (eq x) xs
在span (eq x)
这里尤其重要,因为x
它将是新组的第一项。
x
因此,Since不是列表中的前一个值。如果我们这样运行groupBy
list [5, 3, 2, 1, 6, 4, -2]
,我们得到:
列表 | 当前列表 | x=? | 检查 | 结果 |
---|---|---|---|---|
[5,3,2,1,6,4,-2] |
[8] |
8 |
/ |
/ |
[5,3,2,1,6,4,-2] |
[8] |
8 |
5 |
False |
[3,2,1,6,4,-2] |
[5] |
5 |
/ |
/ |
[3,2,1,6,4,-2] |
[5] |
5 |
3 |
False |
[3,2,1,6,4,-2] |
[3] |
3 |
/ |
/ |
[2,1,6,4,-2] |
[3] |
3 |
2 |
False |
[2,1,6,4,-2] |
[2] |
2 |
1 |
False |
[1,6,4,-2] |
[2] |
2 |
/ |
/ |
[1,6,4,-2] |
[2] |
2 |
1 |
False |
[6,4,-2] |
[1] |
1 |
/ |
/ |
[4,-2] |
[1,6] |
1 |
6 |
True |
[-2] |
[1,6,4] |
1 |
4 |
True |
[] |
[-2] |
-2 |
/ |
/ |
尤其是我们比较x=1
和y=4
重要的情况。如果x
只是前一个值,我们应该开始生成一个新列表,但由于x
是列表的第一项,情况并非如此。
通常你应该只使用等价关系 ~ [wiki],这种关系是:
x ~ x
确实如此;x ~ y
当且仅当y ~ x
;和x ~ y
并y ~ z
暗示那个x ~ z
。你的等价关系不是自反的,也不是对称的。因此,这不是一个可以使用的有效函数groupBy
。