簡體   English   中英

OCaml中的尾遞歸

[英]Tail recursion in OCaml

我正在嘗試使用Tail遞歸在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功能的期望是什么,為什么將結果歸類為怪異的。 對我來說,結果與代碼匹配。 對我來說很奇怪的是,盡管您正在解構l1l2 ,但是您並未使用解構的結果,而是將整個列表l1l2到累加器中。

方法應如下,從第一個列表中獲取一個元素,將該元素添加到累加器中,然后切換列表。 因此,該算法的歸納步驟如下:

 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 []

在歸納步驟中,我們采用較小的元素,並繼續兩個列表:較小元素的所有者的尾巴(因為它已移至累加器中),第二個列表已被完整處理(因為未累積任何內容)從中)。 由於我們在元素之前,它們將以相反的順序排列,因此我們需要做一些事情來反轉結果(通常需要權衡尾遞歸)。 基本情況允許我們在一個或另一個列表較短的情況下縮短算法,並且不再需要一個一個地比較它們,只需將較長列表的其余部分附加到累加器zs 我們使用List.rev_append將列表的剩余尾部追加到累加器中。 此功能會將第一個列表的反向版本放在第二個列表的前面。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM