0

可以使用 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>  

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

4

2 回答 2

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

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

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

于 2015-04-07T02:14:48.420 回答
2

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

我认为您的代码不应该依赖于这种棘手的行为。对于这个特定的示例,正​​如@ivg 的回答中所建议的,您应该使用Lwt_list模块中的函数。

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

于 2015-04-07T16:48:21.740 回答