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?