F# Conditional Branch With Async

Viewed 133

I have a method that conditionally calls an async task:

let processMsg (msg : SocketMessage) =
    task{
        //....
        //....
        let user =
            if msg.User.IsSpecified && (msg.User.Value :? IUser) then
                user.Value :?> IUser
            else
                //Compiler: This construct may only be used within a computation expression
                let! user' = rest.GetUserAsync(UserId, config.restOptions)
                user'
        //....
        //....
    }

The compiler is complaining that I have to be within a computation expression. I thought I was. The only way I could get it to work is to split it out into an async child method:

let getUserAsync (user : SocketUser) =
    task{
        if user.IsSpecified && (user.Value :? IUser) then
            return user.Value :?> IUser
        else
            let! user' =
                rest.GetUserAsync(UserId, config.restOptions)
            return (user' :> IUser)
    }

Now I have an additional async context just to handle a rare corner case. Is there a better way to handle this?

1 Answers

The inside of let user = ... is not a computation expression. The let itself is inside a computation expression, but whatever is inside it is not. So you can't use let! in there.

The way to do what you're trying to do is to turn that let into a let! and then make sure that its right-hand side is a Task:

    let! user =
        if msg.User.IsSpecified && (msg.User.Value :? IUser) then
            Task.FromResult(user.Value :?> IUser)
        else
            rest.GetUserAsync(UserId, config.restOptions)
Related