为什么Haskell中的groupBy需要检查两个变量

Sri*_*vas 2 haskell

我在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)值"不起作用?两个条件都应该相同吗?如果它们不同会发生什么.请举例说明.

dup*_*ode 5

Lignum的答案解释了为什么groupBy谓词有两个论点.换句话说,groupBy设置边界,你需要两面来定义边界.

两个条件都应该相同吗?如果它们不同会发生什么.

是的,他们应该.正如Data.List文档说明......

假设谓词定义了等价.

换句话说,如果p :: a -> a -> Bool是你传递给的谓词groupBy,则所有......

  • p x x = True
  • p x y = p y x
  • 如果p 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)

(它出错的原因是谓词的等同性保证是通过实现来实现groupByspan.)


最后,有一种更好的编写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)