【问题标题】:Use fold to count the number in range使用 fold 计算范围内的数字
【发布时间】:2021-07-02 13:48:30
【问题描述】:

我有一个任务:

使用 fold 计算范围内的数字。使用 int list * int * int -> int 类型完成下面的函数 numberInRange,它接受三个参数(int list, int, int)并返回一个 int,其计数在 lo 和 hi 之间。

fun fold (f, acc, xs) =
    case xs of
         [] => acc
       | x::xs' => fold (f, f (acc, x), xs')

fun numberInRange (xs, lo, hi) = (* ... *)

val myList = [1, 2, 3, 4, 5, 6, 7, 8, 9]

val x = numberInRange (xs, 2, 7)

谁能告诉我怎么做,我正在为我的作业这个问题而苦苦挣扎

【问题讨论】:

  • 对我来说,这个函数的目的不是很明显......“一个在 lo 和 hi 之间计数的 int”是什么意思? lohi 不只是 hi - lo 之间的计数如何?如果你能提供一个或多个例子,或者更清楚的解释,你会更容易解决这个任务。
  • 基本上,我有一个正确的数字列表,比如说 [1, 2, 3, 4, 5]。我需要一个将列表用作一个参数和一个范围的函数。假设范围的下限是 2,hi 是 5。我需要它告诉我 2 到 5 之间,有 4 个数字
  • 我相信 hi 和 lo 不是索引,而是数字本身
  • 哦!所以它计算xs中有多少数字在lohi的封闭区间内!哇,不知道为什么我很难理解。
  • 我认为知道这种类型的折叠是对非常常见的“用列表的头部做某事 (x) 和在其尾部递归的结果 (@987654329) 的抽象可能会有所帮助@)" 模式。

标签: sml smlnj


【解决方案1】:

虽然您可以使用fold 来解决此练习,但由于您似乎在尝试之前就卡住了,我建议您改为返回一步并应用列表递归。一次从输入列表中取出一个元素:如果在区间内,则在结果中加一,否则不加。

fun numberInRange ([], lo, hi) = ...
  | numberInRange (x::xs, lo, hi) =
    if ...
    then ...
    else ...

一些引导性问题:

  • 什么是空列表的好的返回值?
  • 函数什么时候应该调用自己?

一旦您有了任何一种解决方案,将其转换为使用fold 的解决方案就变得更容易了。

【讨论】:

  • 中肯的建议。 (当我确定有折叠但我看不到它时,我通常会这样做。)
【解决方案2】:

fold 接受三个参数,倒序最容易解释:

  • 第三个 xs 是要处理的列表。
  • 第二个accxs 为空时的结果。
  • 第一个 f 是用于将 accxs 的元素依次组合的函数。

由于fold 的递归性质,一次调用的f 的结果将用作下一次调用的acc。这是有道理的,因为如果列表的其余部分为空(意味着我们已经到达列表的末尾),递归调用的acc 将是结果;所以整体fold 的结果是最后一次调用f 的结果。名称 acc 是“累加器”的缩写,但将其视为“部分结果”或“正在进行的结果”会有所帮助:它是我们已经处理的列表部分的结果。

所以,例如:

  • fold f acc []acc
  • fold f acc [a]f (acc, a)
  • fold f acc [a, b]f (f (acc, a), b)
  • fold f acc [a, b, c]f (f (f (acc, a), b), c)

对于您的情况,希望很清楚您需要 xs 成为 xs(因为这是您需要处理的列表),并且您需要 acc 成为 0(因为这是结果如果xs 为空,则需要)。

那么,就剩下f。请记住,如果x 是列表的一个元素,而acc 是所有元素之后的结果 before x,那么f (acc, x) 需要给出所有元素之后的结果向上x

因此,在您的情况下,f (6, 18) 需要是“列表中位于 hilo 之间的元素的数量,如果列表以 18 结尾并且在此之前有 6 个这样的元素。 "换句话说,如果18 在所需范围内,则它需要为7,否则为6。你知道怎么做吗?


现在,我应该指出,以上内容有时被称为“应试者”的解决方案,它利用了如果没有解决方案,您将不会被分配这个问题这一事实。具体来说,以上假设numberInRange 可以使用fold 实现,并且进一步,numberInRange 可以实现为仅使用适当参数对fold 的单个调用。碰巧的是,这个假设是正确的。但是,即使 numberInRange 无法 被实现为对 fold 的单个调用,上述方法也会给我们一个答案(例如,如果一些后处理是必填)——只是答案是错误的!因此,一旦你得到答案,检查它以确保它确实按照numberInRange 应该的方式运行是很重要的。 (并且稍微测试一下是个好主意。即使是伟大的 Donald Knuth 也曾写道,“当心上述代码中的错误;我只是证明它是正确的,没有尝试过。”)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-15
    • 1970-01-01
    相关资源
    最近更新 更多