在Ocaml上附加两个列表

时间:2015-03-17 01:04:59

标签: list recursion ocaml

所以这是附加两个列表的一种方法:

let rec append l1 l2 =
  match l1 with
  | h :: t -> h :: append t l2
  | [] -> l2

但我正在尝试编写一个追尾的尾递归版本。 (在调用递归函数之前解决问题)。

到目前为止,这是我的代码,但是当我尝试在第一个if语句中添加append时,代码因为奇怪的原因而出现故障。

let list1 = [1;2;3;4]
let list2 = [5;6;7;8]



let rec append lista listb =
  match listb with
  | h :: taillist -> if taillist != []  then 
  begin 
    lista @ [h];
    (* I cant put an append recursive call here because it causes error*)
  end else
  append lista taillist;
 | [] -> lista;;


append list1 list2;;

感谢任何帮助,谢谢。

7 个答案:

答案 0 :(得分:5)

将非尾递归列表算法转换为尾递归列表算法的最简单方法是使用累加器。考虑使用第三个列表重写代码,这将累积结果。使用cons(即::)将新元素添加到第三个列表,最后您将得到连接结果。接下来,您只需要使用List.rev et voila来反转它。

答案 1 :(得分:3)

为了完整起见,有一个尾递归append

let append l1 l2 =
  let rec loop acc l1 l2 =
    match l1, l2 with
    | [], [] -> List.rev acc
    | [], h :: t -> loop (h :: acc) [] t
    | h :: t, l -> loop (h :: acc) t l
    in
    loop [] l1 l2

我建议解决99 problems来学习这个习语。

答案 2 :(得分:2)

对您的代码提出几点意见:

  1. 使用@定义列表追加函数似乎是作弊,因为这已经是一个附加两个列表的函数: - )

  2. 您的代码就像OCaml是一种命令式语言一样;也就是说,您似乎希望表达式lista @ [h]来修改lista的值。但是OCaml并不是这样的。 OCaml中的列表是不可变的,lista @ [h]只计算新值而不更改任何先前的值。您需要在递归调用中传递此新值。

  3. 正如@ivg所说,解决问题最直接的方法是使用累加器,最后使用列表反转。这是具有不可变列表的语言中常见的习语。

答案 3 :(得分:2)

使用常量堆栈空间的版本,使用几个标准函数实现(在展开定义后,您将获得尾递归解决方案):

let append xs ys = List.rev_append (List.rev xs) ys

顺便提一下,一些OCaml库以非常复杂的方式实现append函数: (1)在Core_kernel库中查看core_list0.ml:搜索" slow_append"和" count_append" (2)或电池库中的batList.mlv

答案 4 :(得分:0)

您问题的可能答案可能是以下代码:

let append list1 list2 = 
 let rec aux acc list1 list2 = match list1, list2 with 
  | [], [] -> List.rev(acc)
  | head :: tail, [] -> aux (head :: acc) tail []
  | [], head :: tail -> aux (head :: acc) [] tail
  | head :: tail, head' :: tail' -> aux (head :: acc) tail (head' :: tail')
 in aux [] list1 list2;

这与你帖子中另一位评论者给出的代码非常相似,但是这个代码更详尽,因为我添加了一个案例,如果list2从开头是空的而list1不是

答案 5 :(得分:0)

这是一个更简单的解决方案:

let rec apptr l k =
    let ln = List.rev l in
    let rec app ln k acc = match ln with
        | [] -> acc
        | h::t -> app t k (h::acc) in
    app ln k k
;;

答案 6 :(得分:0)

利用延续性的另一种尾递归解决方案(F#):

let concat x =
  let rec concat f = function
  | ([], x) -> f x
  | (x1::x2, x3) ->  concat (fun x4 -> f (x1::x4)) (x2, x3)
  concat id x