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>  

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

首先,在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

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

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

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

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

最好看看Lwt_list模块的实现,看看它是如何实现的。同样的建议也适用于OCaml标准库。

相关内容

  • 没有找到相关文章

最新更新