简体   繁体   English

Haskell使用高阶函数来计算列表中有多少项

[英]Haskell using Higher-Order Functions to count how many items there are in a list

I'm trying to write a line of Haskell that count the number of items in a list that are between two stated upper and lower bounds, eg countBetween 3 6 [5, 9, 2, 4, 6, 3, 1, 4] = 5 since 5, 4, 6, 3 & 4 are between the bounds 3 and 6. 我正在尝试编写一行Haskell,以对列表中两个规定的上限和下限之间的项目数进行计数,例如countBetween 3 6 [5, 9, 2, 4, 6, 3, 1, 4] = 5因为5、4、6、3和4在边界3和6之间。

So far I have: 到目前为止,我有:

countBetween x1 x2 = filter (>=x1) . filter (<=x2)

Which filters the list to only include numbers that are within those bounds, but I don't know how to count how many items that list possesses. 哪个过滤器列表仅包含那些范围内的数字,但我不知道如何计算列表拥有的项目数。 My initial thoughts is that it would use foldr ? 我最初的想法是,它将使用文件foldr

To answer this directly, there's a Haskell tool called hoogle . 为了直接回答这个问题,有一个称为hoogle的Haskell工具。 We'd expect the type of a length function to be [a] -> Int and if we search this verbatim in hoogle we end up with 我们希望length函数的类型为[a] -> Int ,如果我们在搜索中逐字搜索,最终得到

 length :: [a] -> Int

So 所以

countBetween x y = length . filter (>= x) . filter (<= y)

Note the dot since we're continuing to compose functions. 注意点,因为我们正在继续编写函数。

To turn my comment into an answer: 要将我的评论变成答案:

You need to use the length function. 您需要使用length功能。 In this case you would compose it with what you already have as 在这种情况下,您可以将其与已经拥有的

countBetween lower upper = length . filter (>= lower) . filter (<= upper)

Alternatively, you could define your function with its full arguments as 另外,您可以将函数的完整参数定义为

countBetween lower upper xs = length $ filter (>= lower) $ filter (<= upper) xs

The general rule of thumb for eta reduction is to first turn all your $ s into . 减少eta的一般经验法则是首先将您的所有$变成. s and add a $ before the last argument, so the above line becomes s并在最后一个参数之前添加$ ,因此上一行变为

countBetween lower upper xs = length . filter (>= lower) . filter (<= upper) $ xs

Then you look to see if the last argument to your definition is also the last argument to your expression, and it's the only place in your expression that the argument appears 然后,您查看定义的最后一个参数是否也是表达式的最后一个参数,并且它是表达式中唯一出现该参数的位置

countBetween lower upper xs = length . filter (>= lower) . filter (<= upper) $ xs
--                       ^                                                     ^

These can now be removed, leaving you with 现在可以将其删除,让您

countBetween lower upper = length . filter (>= lower) . filter (<= upper)

Then repeat. 然后重复。 In this case, you can't eta reduce any more (easily), so you're done! 在这种情况下,您无法再(轻松)进行eta减少,那么就完成了!

I would also recommend defining your functions with full arguments to begin with then slowly introducing point free versions. 我还建议先使用完整的参数定义函数,然后再慢慢引入无点版本。 Sometimes it's fun to find clever ways to eta reduce expressions, but while it's possible to push it further with some definitions, it isn't always recommended. 有时,找到巧妙的方法来对表达式进行eta简化会很有趣,但是尽管可以通过一些定义将其进一步推广,但并不总是建议这样做。 Only do it where it's natural and makes it easier to read. 仅在自然且易于阅读的地方使用。 For example, using the pointfree tool from the pointfree package, you can eta reduce your definition all the way to 例如,使用pointfree包中的pointfree工具,您可以将定义完全减少到

 countBetween = ((length .) .) . (. (filter . flip (<=))) . (.) . filter . flip (>=)

But this is hardly readable. 但这很难理解。 Don't do this. 不要这样

While using the built-in length function is certainly preferrable, here's a solution using a "poor man's length" with foldr: 虽然最好使用内置的长度功能,但以下是将“可怜的人的长度”与文件夹一起使用的解决方案:

countBetween x1 x2 = foldr (\v len -> len + 1) (0) . filter (>= x1) . filter (<= x2)

The length is computed by foldr: 长度由文件夹计算:

  • we start with an accumulator of 0 我们从0的累加器开始
  • for every list element v, we simply add 1 to our accumulator 对于每个列表元素v,我们只需将1加到累加器

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 使用高阶函数和Lambda微积分在Haskell中操作列表 - Manipulating Lists in Haskell using Higher-Order Functions and Lambda Calculus 在Racket中,如何使用struct而不是仅使用高阶函数或递归来查找列表的长度 - In Racket how do i find the length of a list using struct instead of just using only higher-order functions or recursion F#将函数转换为使用高阶函数 - F# Transforming function into using higher-order functions Haskell:列表理解是高阶函数吗? - Haskell: Are list comprehensions higher order functions? 使用高阶函数的OCaml错误过滤器列表 - OCaml error filter list using higher order functions 如何使用高阶 function(例如 lapply 或 map)而不是 for-loop 来过滤基于特定索引的数据帧列表? - How to use higher-order function (e.g. lapply or map) instead of for-loop to filter through a list of data frames based on certain index? 列表中项目的降序计数 - Count of items in a list in descending order 包含递归和高阶函数的Haskell列表 - A Haskell List Involving Recursion and High Order Functions &#39;Map&#39;高阶Haskell函数 - 'Map' higher order Haskell function 如何按降序计算列表列表中单个项目的出现次数? - How to count the occurrences of single items in a list of lists in descending order?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM