我对函数式编程完全陌生;这是SML的家庭作业。
我有一个整数列表,我正在尝试获取有序对的列表,其中该对的第二个条目是第一个条目出现在初始列表中的次数。
例如:
[2,3,3,5] => [(2,1),(3,2),(5,1)]
我不希望有人实现这个,而是让我知道我正在寻找什么类高阶函数,和/或指向正确方向的指针。同样,对于函数式编程来说还是全新的,甚至是SML语言的新功能。
我最初的想法是我想使用map
,但我无法弄清楚如何跟踪或合并类似的项目。我只是成功地将每个项目变为有序对,第二个条目等于1 ......完全没用。
答案 0 :(得分:3)
所以,为此你可能想要使用折叠,比如foldl
。
一般情况下,在决定是使用map
还是折叠(此处我将折叠表示为foldl
或foldr
)时,您可以使用以下经验法则:< / p>
如果您想要的列表与您输入的列表具有完全相同的元素数,则可能需要map
。否则,你需要折叠。
推理如下:对于列表中的每个元素,map
在输出中生成转换后的元素。另一方面,折叠更为通用,可以做任何你想做的事情。 (而且你确实可以使用折叠实现map
。这并不意味着你当然不需要让事情变得不必要复杂。)
为了完整起见,让我简单解释折叠是如何工作的。折叠遍历列表(左侧为foldl
,右侧为foldr
,因此为名称),一次在累加器中构建一个元素。
让我们在一个例子中看到它:
foldl (fn (e, a) => e + a) 0 [5, 3, 7, 10]
这里e
是我们当前正在使用的元素,a
是累加器变量(即当前结果)。我们从a = 0
开始,因为我们将0
指定为起始值。
| e | a | new a
-------------------------
| 5 | 0 | 5 + 0 = 5
| 3 | 5 | 3 + 5 = 8
| 7 | 8 | 7 + 8 = 15
| 10 | 15 | 10 + 15 = 25
| | 25 |
这为我们提供了a
的最终25
,我们看到该函数总结了列表中的元素。请注意,在任何迭代中,a
的值是到目前为止列表中元素的总和,以及我们每个步骤如何扩展此列表以包含一个元素。
这是我建议的解决此问题的方法。
a
的基本值应该是什么。 (与将[]
作为输入的结果相同。)答案 1 :(得分:0)
除了使用折叠之外,还有另一个提示:由于[(2,1),(3,2),(5,1)]
是最终结果,因此折叠使用的累积函数的返回值可能具有此类型; (int * int) list
。然后,您已将问题缩小为
foldl (fn (elem, acc) => ...) [] xs
其中f
应插入elem
,例如5
,accum
,例如[(2,1),(3,2)]
。 f
可以被认为是插入函数,或者等效地,调用这样的插入函数,只要它产生类似[(2,1),(3,2),(5,1)]
的东西(即,查看已经找到的元素,如果找到则增加它,或者插入它)如果没有找到,则计数为1。