如何从异步表达式中提前 return

How to early return from async expression

loadCustomer 有一个 return 类型的 Async<Result<Customer, string>>,我只想在调用 loadCustomer 没有 return 错误时执行 loadData。如何在不使用第三方 asyncResult 表达式或自己编写的情况下实现此目的?

let getCustomerNameAndAmount customerId dataId =
    async {
        let! customer = loadCustomer customerId
        let! data = loadData dataId
        return customer |> Result.bind (fun c -> Ok (getNameOfCustomer c, data.Amount))
    }

您缺少的操作是('a -> Async<Result<'b, 'e>>) -> Result<'a, 'e> -> Async<Result<'b, 'e>>

这可以写成:

let asyncResultBind<'a, 'b, 'e> (f : 'a -> Async<Result<'b, 'e>>) (a : Result<'a, 'e>) : Async<Result<'b, 'e>> =
    match a with
    | Ok v -> f v
    | Error x -> async {return Error x}

现在您可以将 getCustomerNameAndAmount 写为:

let getCustomerNameAndAmount customerId dataId =
    async {
        let! customer = loadCustomer customerId
        return! asyncResultBind
            (fun c ->
                async {
                    let! data = loadData dataId
                    return Ok (getNameOfCustomer c, data.Amount)
                }
            )
            customer
    }

当然也可以写成inline,不用抽象asyncResultBind:

let getCustomerNameAndAmount customerId dataId =
    async {
        match! loadCustomer customerId with
        |Ok c ->
            let! data = loadData dataId
            return Ok (getNameOfCustomer c, data.Amount)
        |Error e ->
            return Error e
    }