简体   繁体   中英

return position in an async block, in F#

I have the following code:

let private SendOk (payload: 'a) : WebPart =
    payload |> Json.serialize |> OK >=> Writers.setMimeType "application/json"


let getBTCBalance (addresses: string list) : Async<WebPart> =
    async {
        try
            let! reply = blockExplorer.GetMultiAddressAsync addresses |> Async.AwaitTask
            return reply.Addresses |> Seq.map (fun x -> x.FinalBalance.GetBtc()) |> SendOk
        with
        | :? ArgumentNullException as ex -> return BAD_REQUEST    ex.Message
        | ex                             -> return INTERNAL_ERROR ex.Message
    }

It's using the Suave web server, and both paths (ok and errors) return an object of type WebPart .

If I try to move the return statement to wrap everything else, I get the following code:

let getBTCBalance (addresses: string list) : Async<WebPart> =
    async {
        return ( 
            try
                let! reply = blockExplorer.GetMultiAddressAsync addresses |> Async.AwaitTask
                reply.Addresses |> Seq.map (fun x -> x.FinalBalance.GetBtc()) |> SendOk
            with
            | :? ArgumentNullException as ex -> BAD_REQUEST    ex.Message
            | ex                             -> INTERNAL_ERROR ex.Message
        )
    }

The try/with block should return a WebPart object and I thought it would read better by having a single return wrapping it all.

The compiler doesn't agree:

[FS0750] This construct may only be used within computation expressions

I do not understand why this happens. Can anyone explain it to me?

That's because you're using let! .

let! creates a breaking point in the async computation, splitting the code in two, with second part passed as a continuation (see this answer for how that works).

You can't return the whole thing as a single expression, because it's not, in fact, a single expression, it only looks like one. In reality, your function ends after let! and a totally separate function begins.

Here's a simplified version of your problem:

let f = async {
  return (let! x = doSomethingAsync)
}

Does that give you a better idea of what's wrong?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM