4
\$\begingroup\$

I have a simple implementation for "Async.sequence" (the name came from here), but I would like someone to review it for performance, tail call optimization, and functional style.

It has the following signature, which is similar to Async.Parallel:

Async<'a> list -> Async<'a list>

Async.Parallel would be ideal for performance, but it may be important to run the operations in order even though they happen to be async.

let sequence list =
    let rec loop l acc =
        async {
            match l with
            | [] ->
                return List.rev acc
            | h::t ->
                let! h' = h
                return! loop t (h'::acc)
        }
    loop list []

Update

I came up with a minimal implementation built from other basic operations: map + apply (to get map2) and retn. cons is just a helper for the :: operation, since that is not actually a function in F#.

let sequenceList list =
    List.foldBack (map2 cons) list (retn [])

It is probably better to use a library already built, but I like defining these functions myself to better understand how the operations relate. Now that I have the formulation of sequence, I can literally copy and paste this code into my Result module which also has its own map2 and retn defined, and it will work the same.

\$\endgroup\$
1
\$\begingroup\$

As far as I can tell, this should be properly tail-call optimized (see this post), but I haven't actually checked.


Consider using AsyncSeq, it could make dealing with asynchronous collections easier.

\$\endgroup\$
  • \$\begingroup\$ I may consider AsyncSeq, but so far sequence is the only Async/List combination I've needed and I didn't see a function in that library to address it. \$\endgroup\$ – Kasey Speakman Aug 1 '16 at 18:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.