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