Lwt和递归函数

时间:2015-04-07 01:07:42

标签: ocaml tail-recursion ocsigen ocaml-lwt

使用Lwt.return作为递归函数的最终调用是否可以?

我有一个编译好但运行不正常的函数,它看起来像下面的函数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>  

我很确定我做错了。但是我使用的实际功能比这个例子复杂得多,所以我很难调试它。

2 个答案:

答案 0 :(得分:6)

首先,处理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

这意味着,你甚至不需要编写这样的函数,因为它已经存在了。

最后,原始实现中的递归没有问题。您提供的功能是尾递归。

答案 1 :(得分:2)

这取决于g是否返回已经计算过的lwt线程,例如return (),或者是由lwt调度程序稍后调度和唤醒。在前一种情况下,可能会立即调用fun () -> f (List.tl x) g而不是稍后调度,这可能会增加堆栈,具体取决于正在进行的优化。

我认为你的代码应该依赖于这种棘手的行为。对于这个特殊的例子,正如@ ivg的回答所建议的那样,你应该使用Lwt_list模块中的函数。

查看Lwt_list模块的实现以了解它是如何完成的,这是一个好主意。同样的建议也适用于OCaml标准库。