1

我有以下代码:

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
    }

它使用的是 Suave Web 服务器,两个路径(正常和错误)都返回WebPart类型的对象。

如果我尝试移动 return 语句来包装其他所有内容,我会得到以下代码:

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
        )
    }

try/with 块应该返回一个 WebPart 对象,我认为用一个返回来包装它会更好读。

编译器不同意:

[FS0750] 此构造只能在计算表达式中使用

我不明白为什么会这样。谁能给我解释一下?

4

1 回答 1

2

那是因为你正在使用let!.

let!在异步计算中创建一个断点,将代码分成两部分,第二部分作为延续传递(请参阅this answer了解其工作原理)。

您不能将整个内容作为单个表达式返回,因为实际上它不是单个表达式,它只是看起来像一个。实际上,您的函数结束后let!,一个完全独立的函数开始。

这是您的问题的简化版本:

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

这能让你更好地了解问题所在吗?

于 2021-03-15T19:47:56.790 回答