我在Haskell中经历了groupBy,我理解的是groupBy函数接受List和条件,并根据指定的条件对元素进行分组.
let value = [-3,-5,-1,1,1,1,2,3,-1,-2]
groupBy (\x y -> (x > 0) == (y > 0)) value
Run Code Online (Sandbox Code Playgroud)
它工作正常,但为什么我们应该在lambda函数中给出两个变量?为什么"groupBy(> 0)值"不起作用?两个条件都应该相同吗?如果它们不同会发生什么.请举例说明.
Lignum的答案解释了为什么groupBy谓词有两个论点.换句话说,groupBy设置边界,你需要两面来定义边界.
两个条件都应该相同吗?如果它们不同会发生什么.
是的,他们应该.正如Data.List文档说明......
假设谓词定义了等价.
换句话说,如果p :: a -> a -> Bool是你传递给的谓词groupBy,则所有......
p x x = Truep x y = p y xp x y && p y z那么p x z......应该坚持.如果不是这样的话会发生奇怪的事情.例如,我们可能一开始认为......
groupBy (\x y -> (x > 0) == (y < 0)) [-1,2,-3,-4,2,1,2,-3,1,1,2]
Run Code Online (Sandbox Code Playgroud)
...将产生由零和零以下元素交替组成的组.相反,我们得到了虚假的结果:
GHCi> groupBy (\x y -> (x > 0) == (y < 0)) [-1,2,-3,-4,2,1,2,-3,1,1,2]
[[-1,2],[-3],[-4,2,1,2],[-3,1,1,2]]
Run Code Online (Sandbox Code Playgroud)
(它出错的原因是谓词的等同性保证是通过实现来实现groupBy的span.)
最后,有一种更好的编写groupBy谓词的方法:使用onfrom Data.Function:
GHCi> groupBy ((==) `on` (> 0)) value
[[-3,-5,-1],[1,1,1,2,3],[-1,-2]]
Run Code Online (Sandbox Code Playgroud)
(g `on` f) x y = g (f x) (f y).你甚至可以定义:
-- A more general type: Eq b => (a -> b) -> [a] -> [[a]]
groupBySingle :: (a -> Bool) -> [a] -> [[a]]
groupBySingle p = groupBy ((==) `on` p)
Run Code Online (Sandbox Code Playgroud)