【问题标题】:Need hints (not code) converting this recursive function to tail recursive?需要提示(不是代码)将此递归函数转换为尾递归吗?
【发布时间】:2013-01-31 18:04:27
【问题描述】:

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

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)

现在你可以看到这是一个递归函数,我想将它转换为一个尾递归函数。我熟悉尾递归的示例,但我看不到如何在上面的函数中做到这一点

【问题讨论】:

  • 你也不应该得到“提示”,正如你的作业中所指定的那样。请重新观看最后三堂课。
  • 你看过讨论板吗?它充满了它们。来到这里是因为那里没有太多帮助解决这个问题,我不想在那里发布我的代码

标签: sml


【解决方案1】:

当你想到尾递归时,下一个你想到的应该是“累加器”。

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

在这种情况下,您所做的计算是将两个列表放在一起。所以解决方案是在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) = ...

【讨论】:

  • 非常感谢。我再试一次。
  • 我最终得到了一个可行的解决方案,但我不确定如何验证它是尾递归的。有办法吗?
  • 嗯...看看你的递归调用。结果是否用于任何计算?如果是,则不是尾递归。
猜你喜欢
  • 2021-12-16
  • 1970-01-01
  • 1970-01-01
  • 2016-01-06
  • 2019-09-14
  • 2023-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多