在过滤器中考虑列表的其余部分

Stu*_*orn 2 haskell filter

我需要在列表中显示后继较大的元素的数量。例如,在列表 [3,7,2,1,9] 中,我的函数应该返回 2,因为 7 大于 3 并且 9 大于 1。
为了做到这一点,我想使用过滤器函数:

greaterElems :: Ord a => [a] -> Int
greaterElems [] = 0
greaterElems [x] = 0
greaterElems (x:xs) = length (filter (< head xs) (x:xs))
Run Code Online (Sandbox Code Playgroud)

然而,这并不像预期的那样工作:似乎 Haskell 总是考虑列表的第二个元素,好像“head xs”只计算一次,但这对我来说似乎不正常,因为 Haskell 是懒惰的。
我错过了什么,我该如何修复我的代码以实现我的目标?

Wil*_*sem 6

您可以利用zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]我们传递列表的位置及其尾部。的确:

sucGreater :: Ord a => [a] -> [Bool]
sucGreater x = zipWith (<) x (tail x)
Run Code Online (Sandbox Code Playgroud)

或者正如@RobinZigmond 所说,我们可以省略尾部,并使用drop

sucGreater :: Ord a => [a] -> [Bool]
sucGreater x = zipWith (<) x (drop 1 x)
Run Code Online (Sandbox Code Playgroud)

对于给定的样本列表,这给了我们:

Prelude> sucGreater [3,7,2,1,9]
[True,False,False,True]
Run Code Online (Sandbox Code Playgroud)

我把它作为一个练习来计算该True列表中s的数量。

  • 关于“tail”的常见警告:最好使用“drop 1”,以防函数传递空列表。 (3认同)
  • @RobinZigmond:这里没关系,因为“zipWith”将首先评估第一个参数。因此,即使你传递一个空列表,由于懒惰,它也会起作用。 (3认同)