如何修复此SML代码以按预期工作?

时间:2015-09-15 21:17:51

标签: functional-programming sml smlnj

现在我有一个SML功能:

method([1,1,1,1,2,2,2,3,3,3]);

返回:

val it = [[2,2,2],[3,3,3]] : int list list

但我需要它返回:

val it = [[1,1,1,1],[2,2,2],[3,3,3]] : int list list

这是我目前的代码:

- fun method2(L: int list) = 
= if tl(L) = [] then [hd(L)] else  
= if hd(tl(L)) = hd(L) then hd(L)::method(tl(L)) else [hd(L)];

- fun method(L: int list) = 
= if tl(L) = [] then [] else
= if hd(tl(L)) = hd(L) then method(tl(L)) else
= method2(tl(L))::method(tl(L));

正如你所看到的,它错过了第一个方法2调用。关于如何解决这个问题的任何想法?我完全被难倒了。

2 个答案:

答案 0 :(得分:0)

您的问题在if hd(tl(L)) = hd(L) then method(tl(L)) else。这就是说如果尾部的头部等于头部,则继续处理,但不要将其添加到结果列表中。这将跳过第一个连续的相等值的块。我建议将这些功能的职责分开一点。执行此操作的方法是让method2剥离下一个连续的值块,并返回一对,其中第一个元素将删除连续的块,第二个元素将具有剩余的列表。例如,method2([1, 1, 1, 2, 2, 3, 3]) = ([1, 1, 1], [2, 2, 3, 3])method2([2, 2, 3, 3]) = ([2, 2], [3, 3])。现在,您可以继续致电method2,直到该对的第二部分为nil

答案 1 :(得分:0)

我不太确定你要对你的代码做什么。我建议创建一个尾递归辅助函数,它传递三个参数:

1) The list of lists you are trying to build up
2) The current list you are building up
3) The list you are processing

在您的示例中,计算中间某处的典型调用如下所示:

helper([[1,1,1,1]], [2,2],[2,3,3,3])

通过查看最后一个参数([2,3,3,3])的头部以及当前正在构建的列表的头部([2,2]),递归将起作用,因为它们是相同 - 最后一个参数末尾的2被分流到正在建立的列表中:

helper([[1,1,1,1]], [2,2,2],[3,3,3])

在递归的下一步中,然后比较磁头并发现它们是不同的(2!= 3),因此辅助函数将中间列表放在列表列表的前面:

helper([[2,2,2], [1,1,1,1]], [3],[3,3])

中间列表被重新初始化为[3],因此它将开始增长

最终你达到了这样的目标:

帮手([[2,2,2],[1,1,1,1]],[3,3,3],[])

然后将[3,3,3]添加到列表列表中,并返回此列表的 reverse

一旦定义了这样的辅助函数,main方法就会检查一个空列表,如果不是空的话,则初始化对辅助函数的第一次调用。以下代码充实了这些想法 - 使用模式匹配样式而不是hdtl(我不是明确使用这些函数的忠实粉丝 - 它使得代码太像Lisp一样) 。如果这是家庭作业,那么你应该彻底了解它是如何工作的,然后将其翻译成涉及hdtl的代码,因为如果你使用尚未学习的东西,你的教授会认为它是抄袭的。没有成为你自己的工作:

fun helper (xs, ys, []) = rev (ys::xs)
|   helper (xs, y::ys, z::zs) = 
        if y = z 
           then helper(xs, z :: y :: ys, zs)
           else helper((y::ys)::xs,[z],zs);

fun method [] = []
|   method (x::xs) = helper([],[x],xs);