Reputation: 357
Is it ok to use Lwt.return as the final call in a recursive function?
I have a function that compiles fine but does not run properly and it looks like the function f
below. Please assume that there is no issue with any function provided as g
in this example, I am basically just trying to find out if it is ok to have a function with the following form or if there is a better/simpler (and Lwt compliant) way of doing the following:
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>
I am pretty sure that I am doing it wrong. But the actual function I am using is much more complex than this example so I am having a difficult time debugging it.
Upvotes: 0
Views: 522
Reputation: 4909
It depends whether g
returns an lwt thread that is already computed such as return ()
or scheduled and woken up later by the lwt scheduler. In the former case, it's possible that the call to fun () -> f (List.tl x) g
is made right away instead of being scheduled for later, and that could grow the stack depending on what optimizations are happening.
I don't think your code should rely on such tricky behavior. For this particular example, as suggested in @ivg's answer, you should use the functions from the Lwt_list
module.
It's a good idea to look at the implementation of the Lwt_list
module to see how it's done. The same advice goes for the OCaml standard library as well.
Upvotes: 2
Reputation: 35210
First of all the correct way of dealing with lists in OCaml is deconstructing them with pattern matching, like this:
let rec f (xs : string list) (g : string -> unit Lwt.t) =
match xs with
| [] -> return ()
| x :: xs -> g x >>= fun () -> f xs g
The next step would be notice, that you're actually just perform iteration over a list. There is a Lwt_list.iter_s
for this:
let f g xs = Lwt_list.iter_s g xs
That can simplified even more
let f = Lwt_list.iter_s
That means, that you even do not need to write such function, since it is already there.
And finally, there was no issues with recursion in your original implementation. The function that you've provided was tail recursive.
Upvotes: 7