2015-04-07 60 views
0

可以使用Lwt.return作爲遞歸函數中的最終調用嗎?Lwt和遞歸函數

我有一個編譯好但功能不正常的函數,它看起來像下面的函數f。請假定在這個例子中,作爲g提供的任何函數都沒有問題,我基本上只是想知道是否可以使用以下形式的函數或者是否有更好/更簡單(並且符合Lwt)做法如下:

let rec f (x : string list) (g : string -> unit Lwt.t) = 
    match List.length x with 
    | 0 -> Lwt.return() 
    | _ -> g (List.hd x) >>= fun() -> f (List.tl x) g 
;; 
val f : string list -> (string -> unit Lwt.t) -> unit Lwt.t = <fun> 

我很確定我做錯了。但是我使用的實際功能比這個例子複雜得多,所以我很難調試它。

回答

5

的處理OCaml中列出的所有正確的做法首先是與模式匹配解構他們,就像這樣:

let rec f (xs : string list) (g : string -> unit Lwt.t) = 
    match xs with 
    | [] -> return() 
    | x :: xs -> g x >>= fun() -> f xs g 

下一步將通知書的,你實際上只是在執行迭代名單。有此一Lwt_list.iter_s

let f g xs = Lwt_list.iter_s g xs 

,可以簡化甚至更

let f = Lwt_list.iter_s 

這意味着,你甚至不需要寫這樣的功能,因爲它已經存在。

最後,在原始實現中沒有遞歸問題。你提供的功能是尾遞歸。

2

它取決於g是否返回已經計算的lwt線程,例如return()或者由lwt調度程序調度和喚醒。在前一種情況下,可能會立即調用fun() -> f (List.tl x) g而不是稍後安排,並且可能會根據正在發生的優化來增加堆棧。

我不認爲你的代碼應該依賴這種棘手的行爲。對於這個特定的例子,如@ ivg的答案中所建議的那樣,您應該使用Lwt_list模塊的功能。

最好看看Lwt_list模塊的實現,看看它是如何完成的。 OCaml標準庫也有相同的建議。

+1

我會補充一點,看看該模塊的實施可能是一個好主意,只是爲了學習如何處理這種情況。 –