Reputation: 23
loadCustomer has a return type of Async<Result<Customer, string>>
and I only want to execute loadData if calling loadCustomer doesn't return an error. How can I achieve this without using a third party asyncResult
expression or writing my own?
let getCustomerNameAndAmount customerId dataId =
async {
let! customer = loadCustomer customerId
let! data = loadData dataId
return customer |> Result.bind (fun c -> Ok (getNameOfCustomer c, data.Amount))
}
Upvotes: 0
Views: 134
Reputation: 40603
The operation that you are missing is ('a -> Async<Result<'b, 'e>>) -> Result<'a, 'e> -> Async<Result<'b, 'e>>
This can be written as:
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}
Now you can write getCustomerNameAndAmount as:
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
}
Of course, this could also be written inline, without the abstraction of 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
}
Upvotes: 3