Reputation: 4282
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?
Upvotes: 3
Views: 504
Reputation: 15365
this.GetRestaurants()
|> AsyncSeq.filterAsync categoryRepository.IsRestaurantInCategoryAsync name address category
|> AsyncSeq.toListAsync
Upvotes: 0
Reputation: 243041
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) }
Upvotes: 2