2015-04-07 61 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

我会补充一点,看看该模块的实施可能是一个好主意,只是为了学习如何处理这种情况。 –