在SML中迭代多个列表

时间:2013-01-15 23:03:54

标签: sml

我在SML中有两个列表,比如列表A [(a,b,c),(d,e,f)]和列表B [b,e]。我想计算B中每个项目与A中每个三元组的第二个元素匹配的次数。输出应为2.因为be每个在A中出现一次。

这是我的代码到目前为止,但是当我从B中的一个元素移动到另一个元素时,我的计数器总是设置为0.我知道在Java中这只是一个简单的双循环。

fun number_in_months (d : (int * int * int ) list, m : (int) list) = 
    if null m then 0 
    else if null d then number_in_months(d, tl m)
    else if (#2(hd d)) = (hd m) then 1 + number_in_months (tl d, m)
    else number_in_months(tl d, m)

2 个答案:

答案 0 :(得分:5)

代码不会在递归调用之间累积值。可能还有其他逻辑错误。

使用递归和函数累积值是一种常见模式,您可以阅读有关here的更多信息。它的本质是使用headtail解构列表,直到列表为空并在每次调用时累积一些值。下面的sum函数是一个显示此功能的简单示例。这可以根据您的示例进行调整,以便在acc中找到be时累积list A

fun sum(numbers: (int) list) =
  let fun sumR(numbers: (int) list, acc: int) =
    if null numbers
    then acc
    else
      sumR(tl numbers, hd numbers + acc)
  in
    sumR(numbers, 0)
  end

[1,2,3]上运行会发出:

val sum = fn : int list -> int
- sum([1,2,3]);
val it = 6 : int

注意我对此答案有意模糊,因为这是关于编程语言课程的Coursera作业的问题。

答案 1 :(得分:2)

正如您所提到的,它将是任何命令式编程语言中的嵌套/双循环。你实际上缺少的是第二个循环。

你的“内部”循环遍历d的所有元素,一旦完成,你的“外部”循环会尝试弹出m的顶部元素并从头开始,如下所示这行代码:

else if null d then number_in_months(d, tl m)

然而,正如您所看到的,您刚刚测试了列表d是空的,并且您在m的尾部递归调用提供了这个(完全相同的列表),然后它会掉落在每个连续调用的相同情况下,m也为空并返回0。

因此,您缺少的是“保留原始输入列表m的副本”。这可以通过各种方式完成,但内部(辅助)函数是最常用的函数,它甚至“看起来”像嵌套循环

fun number_in_months (d, m) =
    let
      fun nim' ([], y::ys) = nim (d, ys)                 (* 1 *)
        | nim' (_, []) = 0                               (* 2 *)
        | nim' ((_, x2, _) :: xs, yss as (y::ys)) = ...  (* 3 *)
    in
      nim'(d, m)
    end

使用模式匹配,上述代码变得更简单,更不容易出错。在情况1中,“内部”循环遍历d中的所有元素,因此使用来自外部函数的d的递归调用在任何时候都不会更改。在情况2中,“外部”循环遍历了m的所有元素,并且我们返回0(添加的中性元素)。在案例3中,我们进行实际工作。这里使用模式匹配,这样我们就不需要强制执行参数的类型,我们不需要提取三元组的第二个元素,我们已经在变量x2中使用了它。所需要的只是进行计算并使用xsyss进行递归调用。

当这样做的时候,内部(帮助器)函数正在使用原始输入列表d的“副本”并逐步执行其元素(可能会修改它),但是我们总是引用它原始输入列表,我们可以在需要时使用它。