【问题标题】:Haskell using Higher-Order Functions to count how many items there are in a listHaskell 使用高阶函数计算列表中有多少项
【发布时间】:2014-01-15 14:44:25
【问题描述】:

我正在尝试编写一行 Haskell 来计算列表中位于两个规定的上限和下限之间的项目数,例如countBetween 3 6 [5, 9, 2, 4, 6, 3, 1, 4] = 5 因为 5、4、6、3 和 4 介于边界 3 和 6 之间。

到目前为止我有:

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

过滤列表以仅包含在这些范围内的数字,但我不知道如何计算该列表拥有多少项目。我最初的想法是它会使用foldr?

【问题讨论】:

  • length 函数?
  • 在这种情况下如何使用?
  • countBetween x1 x2 = length . filter (>=x1) . filter (<= x2)
  • 谢谢!我已经使用countBetween x1 x2 = length (filter (>=x1) . filter (<= x2)) 很多年了,但它一直没有用,没想到要使用点!干杯

标签: list haskell higher-order-functions


【解决方案1】:

将我的评论变成答案:

您需要使用length 函数。在这种情况下,你可以用你已经拥有的东西来组合它

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

或者,您可以将带有完整参数的函数定义为

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

减少 eta 的一般经验法则是首先将所有 $s 转换为 .s 并在最后一个参数之前添加 $,因此上述行变为

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

然后查看定义的最后一个参数是否也是表达式的最后一个参数,并且它是表达式中唯一出现参数的位置

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

现在可以删除这些,留给您

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

然后重复。在这种情况下,您不能再减少(轻松地),所以您完成了!

我还建议在开始时使用完整的参数定义您的函数,然后慢慢引入无点版本。有时找到 eta reduce 表达式的巧妙方法很有趣,但是虽然可以通过一些定义进一步推动它,但并不总是建议这样做。只在自然且易于阅读的地方进行。例如,使用pointfree 包中的pointfree 工具,您可以将定义一直缩减到

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

但这很难读。不要这样做。

【讨论】:

    【解决方案2】:

    要直接回答这个问题,有一个名为 hoogle 的 Haskell 工具。我们希望 length 函数的类型是 [a] -&gt; Int,如果我们在 hoogle 中逐字搜索,我们最终会得到

     length :: [a] -> Int
    

    所以

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

    请注意点,因为我们将继续编写函数。

    【讨论】:

      【解决方案3】:

      虽然使用内置的长度函数当然是更可取的,但这里有一个使用 foldr 的“穷人长度”的解决方案:

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

      长度由 foldr 计算:

      • 我们从 0 的累加器开始
      • 对于每个列表元素 v,我们只需将 1 添加到累加器中

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-08-04
        • 1970-01-01
        • 1970-01-01
        • 2017-04-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多