Asynchronous F#异步和匿名函数

Asynchronous F#异步和匿名函数,asynchronous,f#,Asynchronous,F#,我有一个方法可以使用此签名执行一些IO: member this.IsRestaurantInCatagoryAsync(restaurantName: string, restaurantAddress: string, restaurantCatagory: string) = async { ///long running methods } 我想在匿名函数中调用它,如下所示: this.GetRestaurants() |> Seq.filter(fun

我有一个方法可以使用此签名执行一些IO:

member this.IsRestaurantInCatagoryAsync(restaurantName: string, restaurantAddress: string, restaurantCatagory: string) =
    async { ///long running methods }
我想在匿名函数中调用它,如下所示:

this.GetRestaurants()
        |> Seq.filter(fun (name, address) -> catagoryRepository.IsRestaurantInCatagoryAsync(name, address,catagory))
        |> Seq.toList

问题是IsRestaurantInCatagoryAsync返回的是异步,而不是bool。我如何让序列过滤器处理它?我应该使用let将异步转换为bool吗!因此,我必须编写一个非匿名函数来分配返回值?

您可以使用
Async.RunSynchronously
来同步运行操作,但这会破坏使用异步工作流来避免编写阻塞代码的意义,因此这不是正确的方法

有不同的方法可以做到这一点——你可以按顺序迭代所有的餐厅(这将一个接一个地处理),或者你可以并行运行过滤(这将使用尽可能多的线程池线程,只要.NET找到合适的线程)

并行版本如下所示:

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 }
请注意,代码都在
async
块中(因为这使它保持异步)。它首先创建一个计算列表,返回带有
None
(跳过餐厅)或
Some
(包括餐厅)的选项,然后运行所有这些选项并使用
Seq过滤
None
值。选择

要按顺序实现这一点,您基本上需要自己的
filter
实现,它被包装在
async
块中。这将是一个很好的起点(尽管不是尾部递归):


是否有计划添加一个Seq.FilterAsync等。。。符合F#规格?
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) }