2

I am translating all my f# code to use async. I am finding it more difficult than expected, and I would like to know if there is a better way or I am missing something.

Take these two functions:

let test1() =
        let y = 
                let x = 
                        let z = f()
                        5 + z
                x + 6
        y + 3

let test2() =
        let z = f ()
        let x = 5 + z
        let y = x + 6
        y + 3

These functions are completely equivalent, but my code happens to be in the style of test1.

It seems that code written like test1 is very costly to translate to async. For example, suppose function f () becomes async:

let f () =
        async{
                return 3
        }

The question is how to translate test1 and test2. It turns out that test2 is rather easy to fix:

let test2Async() =
        async{
        let! z = f ()
        let x = 5 + z
        let y = x + 6
        return y + 3
        }

you just need to type one "async {}" , one "!" and one "return".

But if you do the same with test1, it will not compile:

let test1AsyncWrong() =
        async{
        let y = 
                let x = 
                        let! z = f() // ERROR HERE: we are not in a computation expression, so I can't use !
                        5 + z
                x + 6
        return y + 3
        }

Here is, as far as I know, what you really need to do to properly translate test1:

let test1AsyncRight() =
        async{
        let! y = 
                async{
                let! x = 
                        async{
                        let! z = f()
                        return 5 + z
                        }
                return x + 6
                }
        return y + 3
        }

Notice that I needed to type async{} three times, plus "!" three times and "return" three times.

This seems like an unnecessary and counterintuitive complication. It feels like there is something wrong. Translating code like that will take days if I have to do this.

Am I missing something? What's going on? Thanks for any help.

2
  • Why are you "translating" all your code to async? That's an odd thing to do. Commented Sep 19, 2015 at 21:33
  • I need a responsive WPF gui. I have converted a few low-level functions to async, and then async is "contagious" as you know, so it propagates to everything up to WPF event handlers. Commented Sep 20, 2015 at 6:23

1 Answer 1

3

I don't think there's a nicer way of nesting one async in another. But it could have been worse, imagine doing it without computation workflows.

I'd refactor the "asyncified" code to get rid of the nesting. So for your example I'd have something like this - a regular function that doesn't know anything about async, and an async version that only cares about putting the pieces together.

let test1 z = 
    let y = 
        let x = 
            5 + z
        x + 6
    y + 3

let test1Async() =
    async{
        let! z = f()
        return test1 z 
    }

This is an overly simplistic example of course. Normally you'd have f depending on some arguments, and simply pulling it out of its context like this may not be possible. In that case I'd try to restructure the logic to suit it, without sprinkling asyncs all over the original code. Collect all information needed to run your asyncs, run them, and process the results as separate steps.

let test () = 
    async {
        let inputs = figureOutInputs()
        let! results = doAsyncStuff inputs
        return processResults results
    }

That way you can limit the contagion from spreading too much ;)

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.