asynchronousf#computation-expression

F# program flow question with Async and Option


I'm trying to wrap my head around how to accomplish the following task in F#. The following is a simplified C# pseudocode equivalent I'm looking to replicate.

var x = await GetXAsync();
if (x == null) return "not found";
var y = await GetYAsync(x);
return y;

My initial F# version looks something like:

task {
    let! x = GetXAsync()
    match x with
    | None -> // need to return a hard-coded value here
    | Some x` -> 
                 let! y = GetYAsync(x`)
                 // More code
                 // return some value based on y here
}

Obviously this is terrible, but I'm unsure of how to proceed. Should I attempt a full ROP style of programming here, or is there something simpler?


Solution

  • In your example, you are returning the "not found" string to indicate that something went wrong from a function that otherwise returns strings. I would not do this, because it will be hard to distinguish between the case where everything worked and the case where it did not.

    If the fact that GetXAsync returns null is something that indicates a failure, then I'd just use exceptions. F# async has a nice support for propagating those and you can catch them using try .. with. There is nothing wrong with using exceptions in F# to handle exceptional situations!

    exception InvalidX of string
    
    let GetXAsync() = async { 
      // whetever code that calculates 'failed' and 'result' goes here
      if failed then raise (InvalidX "not found")
      return result }
    

    Then you can just call the functions and exceptions get propagated automatically.

    async {
      let! x = GetXAsync() 
      let! y = GetYAsync(x)
      return y }