Recursion OCaml中的尾部递归

Recursion OCaml中的尾部递归,recursion,ocaml,tail-recursion,Recursion,Ocaml,Tail Recursion,我试图使用尾部递归在OCaml中实现合并函数,但我面临着尴尬的结果。谁能帮我解决这个问题。提前谢谢 let rec merge_helper l1 l2 accum = match l1 with [] -> l2@accum | hd::tl -> (match l2 with [] -> l1@accum |x::xs -> merge_helper tl xs l1@l2@accum);; let merge l1 l2 = merge_helpe

我试图使用尾部递归在OCaml中实现合并函数,但我面临着尴尬的结果。谁能帮我解决这个问题。提前谢谢

let rec merge_helper l1 l2 accum = 
match l1 with
[] -> l2@accum
| hd::tl -> (match l2 with
    [] -> l1@accum
    |x::xs -> merge_helper tl xs l1@l2@accum);;
let merge l1 l2 = merge_helper l1 l2 [];;

merge [1;2;4] [3;4;5];;
- : int list = [4; 5; 2; 4; 4; 5; 1; 2; 4; 3; 4; 5]

首先,您的实现不会在恒定的堆栈空间中运行。
xs@ys
操作不是尾部递归操作,它将进行
List.length xs
调用(因此使用这一数量的堆栈帧)。另外,
merge
函数通常保留顺序。所以您需要有一个比较函数,它将比较列表中的元素。还不完全清楚,您对
merge
函数的期望是什么,以及为什么将结果归类为怪异。对我来说,结果与代码匹配。我觉得很奇怪的是,尽管您正在解构
l1
l2
,但您没有使用解构的结果,而是将整个列表
l1
l2
添加到累加器中

方法如下:从第一个列表中获取一个元素,将该元素添加到累加器中,然后切换列表。因此,该算法的归纳步骤如下:

 let rec loop acc xs ys = match xs with
   ...
   | x::xs -> loop (x::acc) ys xs
但是,如果要合并两个保留顺序的已排序列表,则需要在每个步骤中使用两个列表中最小的元素

let merge cmp xs ys = 
    let rec loop xs ys zs = match xs,ys with
      | [],ss|ss,[] -> List.rev_append zs ss
      | x :: txs, y :: tys -> 
         if cmp x y <= 0 
         then loop txs ys (x::zs)
         else loop xs tys (y::zs) in
    loop xs ys []
让合并cmp xs ys=
让rec循环xs ys zs=将xs,ys与
|[],ss | ss,[]->List.rev_append zs ss
|x::txs,y::tys->

如果cmpxy首先,您的实现没有在恒定的堆栈空间中运行。
xs@ys
操作不是尾部递归操作,它将进行
List.length xs
调用(因此使用这一数量的堆栈帧)。另外,
merge
函数通常保留顺序。所以您需要有一个比较函数,它将比较列表中的元素。还不完全清楚,您对
merge
函数的期望是什么,以及为什么将结果归类为怪异。对我来说,结果与代码匹配。我觉得很奇怪的是,尽管您正在解构
l1
l2
,但您没有使用解构的结果,而是将整个列表
l1
l2
添加到累加器中

方法如下:从第一个列表中获取一个元素,将该元素添加到累加器中,然后切换列表。因此,该算法的归纳步骤如下:

 let rec loop acc xs ys = match xs with
   ...
   | x::xs -> loop (x::acc) ys xs
但是,如果要合并两个保留顺序的已排序列表,则需要在每个步骤中使用两个列表中最小的元素

let merge cmp xs ys = 
    let rec loop xs ys zs = match xs,ys with
      | [],ss|ss,[] -> List.rev_append zs ss
      | x :: txs, y :: tys -> 
         if cmp x y <= 0 
         then loop txs ys (x::zs)
         else loop xs tys (y::zs) in
    loop xs ys []
让合并cmp xs ys=
让rec循环xs ys zs=将xs,ys与
|[],ss | ss,[]->List.rev_append zs ss
|x::txs,y::tys->

如果cmp x y,你期望得到什么结果?@anthonysecema 1 2 3 4 4 5如果你想合并两个有序列表,那么你至少需要对两个元素进行一次比较。你期望得到什么结果?@anthonysecema 1 2 3 4 4 5如果你想合并两个有序列表,然后你需要至少对两个元素进行一次比较。在合并排序中,你应该先将最小的元素和最大的元素进行合并,如果合并步骤的数量不均匀,则只对最终结果进行一次比较。节省了一些时间和内存。是的,使用更高效的
merge\u rev
功能通常很有用。我希望所有列表函数都有一个
?rev
参数。在合并排序中,您应该先合并最小值和最大值,如果合并步骤的数量不均匀,则只对最终结果执行一次。节省了一些时间和内存。是的,使用更高效的
merge\u rev
功能通常很有用。我希望所有列表函数都有一个
?rev
参数。