正如您所提到的,这将是任何命令式编程语言中的嵌套/双循环。您实际上缺少的是第二个循环。
您的“内部”循环遍历 的所有元素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
。所需要做的就是进行计算并使用 and 进行递归xs
调用yss
。
When doing it this way, the inner (helper) function is using a "copy" of the original input list d
and stepping through its elements (potentially modifying it), but we always got a reference to the original input list, which we can use if/when needed.