Functional programming 将包含公共项的列表转换为有序对的列表

Functional programming 将包含公共项的列表转换为有序对的列表,functional-programming,sml,smlnj,Functional Programming,Sml,Smlnj,我对函数式编程一无所知;这是SML的家庭作业 我有一个整数列表,我试图得到一个有序对列表,其中对的第二个条目是第一个条目出现在初始列表中的次数 例如: [2,3,3,5] => [(2,1),(3,2),(5,1)] 我不希望有人实现这一点,而是让我知道我在寻找什么样的高阶函数,和/或一个指向正确方向的指针。同样,对函数式编程来说是全新的,对SML语言来说更是全新的 我最初的想法是我想使用map,但我不知道如何跟踪或合并类似的项目。我只成功地将每个项目转换为第二个条目等于1的有序对。。。

我对函数式编程一无所知;这是SML的家庭作业

我有一个整数列表,我试图得到一个有序对列表,其中对的第二个条目是第一个条目出现在初始列表中的次数

例如:

[2,3,3,5] => [(2,1),(3,2),(5,1)]
我不希望有人实现这一点,而是让我知道我在寻找什么样的高阶函数,和/或一个指向正确方向的指针。同样,对函数式编程来说是全新的,对SML语言来说更是全新的


我最初的想法是我想使用
map
,但我不知道如何跟踪或合并类似的项目。我只成功地将每个项目转换为第二个条目等于1的有序对。。。完全没有用。

因此,对于这一点,您可能需要使用折叠,如
foldl

一般来说,在决定是否使用
map
或fold(这里我把fold理解为
foldl
foldr
)时,可以使用以下经验法则:

如果要输出的列表的元素数与要输入的列表的元素数完全相同,则可能需要一个
映射。否则,你会想要折叠

推理如下:对于列表中的每个元素,
map
在输出中生成一个转换后的元素。另一方面,fold更通用,可以做任何你想做的事情。(您确实可以使用折叠来实现
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
    的基值应该是多少。(与获取
    []
    作为输入的结果相同。)
  • 然后考虑如何从较小的列表中获取结果,并将其展开以包含另一个元素

除了使用折叠,这里还有另一个提示:由于
[(2,1)、(3,2)、(5,1)]
是最终结果,因此fold使用的累加函数的返回值可能具有此类型<代码>(int*int)列表
。然后,您将问题简化为

foldl (fn (elem, acc) => ...) [] xs
其中
f
应将
elem
,例如
5
,插入
acum
,例如
[(2,1)、(3,2)]
f
可以被视为一个插入函数,或者等价地,调用这样的插入函数,只要它生成类似于
[(2,1)、(3,2)、(5,1)]
(即,查找已经找到的元素,如果找到则增加它,如果没有找到则插入计数1)