I have a method that does some IO with this signature:
member this.IsRestaurantInCategoryAsync(restaurantName: string, restaurantAddress: string, restaurantCategory: string) =
async { ///long running methods }
I want to invoke it in an anonymous function like so:
this.GetRestaurants()
|> Seq.filter(fun (name, address) -> categoryRepository.IsRestaurantInCategoryAsync(name, address, category))
|> Seq.toList
The problem is that the IsRestaurantInCategoryAsync returns a async<bool>, not a bool. How do I have the Seq.Filter handle it?
Should I cast the async<bool> to a bool using a let! so then I have to write a non-anonymous function to assign the return?
You could use Async.RunSynchronously to run the operation synchronously - but that would defeat the point of using asynchronous workflows to avoid writing blocking code, so that is not the right way to go!
There are different ways to do it - you could iterate over all restaurants sequentially (which will handle one by one) or you could run the filtering in parallel (which will use as many threadpool threads as .NET finds good).
The parallel version looks like this:
let checkAll = async {
let! all =
[ for r in this.GetRestaurants() -> async {
let! include = catagoryRepository.IsRestaurantInCatagoryAsync(name, address,catagory)
if include then return Some(r) else return None } ]
|> Async.Parallel
let included = Seq.choose id all
printfn "%A" included }
Note that the code is all inside async block (because this keeps it asynchronous). It first creates a list of computations that return options with None (to skip restaurant) or Some (to include restaurant), then runs all of them and filters the None values using Seq.choose.
To implement this sequentially, you'd basically need your own implementation of filter that is wrapped in async blocks. This would be a good starting point (although it is not tail-recursive):
let rec filterAsync f items = async {
match items with
| [] -> return []
| x::xs ->
let! included = f x
let! rest = filterAsync f xs
return (if included then x::rest else rest) }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With