0

我有这个函数,它需要一个字符串列表和一个字符串,然后返回每个列表中所有元素的列表,其中包含传递的字符串但没有传递的字符串。

myfilter([["a","b"],["c","d"],["e","a","x"]], "a") -> ["b","e","x"]

fun myfilter(list : string list list, s : string) =
case list of
    [] =>  []
   |xs::xs' => case all_except_option(s, xs) of (* helper function that does it for a string and a list of strings *)
                   NONE => []
                  |SOME n => if n = xs
                             then myfilter(xs',s)
                             else n@myfilter(xs',s)

现在,正如您所见,这是一个递归函数,我想将其转换为尾递归函数。我熟悉尾递归的示例,但我看不到如何在上面的函数中做到这一点

4

1 回答 1

6

当您认为尾递归时,您认为下一个应该是“累加器”。

一个函数不是尾递归的原因是它必须调用自己来获得一些结果,然后对这个结果做一些事情。如果我们可以将该计算移动到递归调用中,那么它就是尾递归。

在这种情况下,您所做的计算是将两个列表放在一起。所以解决方案是在 a 中声明的函数let ... in ... end,它接受第三个参数 - 累加器。然后,您可以随时将项目添加到累加器中。

一个很好的例子是尾递归阶乘函数。这是正常的阶乘函数:

fun fact 0 = 1
  | fact x = x * fact (x-1)

为了使其尾递归,我们定义了一个局部函数,它接受一个累加器,并在那里进行乘法运算。

fun fact x =
let
  fun fact' 0 acc = acc
    | fact' x acc = fact (x-1) (x*acc)
in
  fact' x 1
end

我们使用 1 作为累加器的起始值,因为乘以 1 没有效果。

好的,除此之外,您还可以做一些小事来改进您的代码。我注意到这里有很多人这样做:

fun foo xs =
case xs of
    []      => ...
  | (x::xs) => ...

这样做会更好:

fun foo []      = ...
  | foo (x::xs) = ...
于 2013-01-31T09:38:10.410 回答