【问题标题】:How to write a function that adds elements of list using tail recursion?如何编写一个使用尾递归添加列表元素的函数?
【发布时间】:2019-04-08 16:34:05
【问题描述】:

我需要在 OCaml 中编写一个函数,在两个不同的递归中添加两个列表的元素:简单和尾。我做了一个简单的:

let rec add1 a b = 
match (a, b) with
      ([], []) -> []
    | (head1::tail1, []) -> head1 :: add1 tail1 []
    | ([], head2::tail2) -> head2 :: add1 [] tail2
    | (head1::tail1, head2::tail2) -> head1 + head2 :: add1 tail1 tail2
;;

它的工作原理是这样的:

add1 [1;2;3] [4;5;6;7];;

这个回报:

int list = [5; 7; 9; 7]

[1+4; 2+5; 3+6; 0+7] : 0 添加到 7 因为在第一个列表中该位置没有元素。

所以,我的问题是:

如何使用尾递归实现它?

【问题讨论】:

  • 你必须处理两个列表长度不同的情况吗?
  • 是的,我需要,在我的第一个函数中,如果在其中一个列表中的相似位置上没有元素,我必须添加 0

标签: function functional-programming ocaml


【解决方案1】:

使这个尾递归的方法是将结果反向构建并在递归中传递并在最后将其反转。

let add1 a b =
  let rec loop acc = function
    | (xs, [])
    | ([], xs) -> List.rev_append acc xs
    | (x::xs, y::ys) -> loop ((x + y)::acc) (xs, ys)
  in
  loop [] (a, b)

注意:如果一个列表比另一个更长,那么您不需要为每个元素添加 0。尾巴已经是结果了。所以我使用 List.rev_append 来反转累积的值并一次性追加剩余的尾部。

注意2:List.rev_append 也可以追加空列表,因此不需要匹配 ([], [])。

【讨论】:

    【解决方案2】:

    尾递归在于具有递归函数,该函数仅执行对自身的调用而无需任何其他操作。

    下面的阶乘不是尾递归的,因为最后一条语句不执行对 fact 的简单调用,而是需要一个乘法:

        let rec fact n = 
            if n = 0 then 1
            else n*(fact (n-1))
    

    通过使用累加器,您可以使此函数尾递归,最后一条语句执行对事实的调用,因此可以使用跳转而不是调用来编译:

        let rec fact n r =
            if n = 0 then r
            else fact (n-1) (r*n)
    

    以及用法:

        fact 5 1
    

    对于您的列表添加,如果两个列表至少具有相同的长度,您可以按照相同的方式进行。

    【讨论】:

      猜你喜欢
      • 2017-03-18
      • 2012-10-26
      • 2014-05-29
      • 1970-01-01
      • 1970-01-01
      • 2016-01-14
      • 2021-11-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多