F#异步和匿名函数

3

我有一个函数,它的签名涉及一些IO操作:

member this.IsRestaurantInCategoryAsync(restaurantName: string, restaurantAddress: string, restaurantCategory: string) =
    async { ///long running methods }

我希望能在一个匿名函数中调用它,代码如下:

this.GetRestaurants()
        |> Seq.filter(fun (name, address) -> categoryRepository.IsRestaurantInCategoryAsync(name, address, category))
        |> Seq.toList

问题在于IsRestaurantInCategoryAsync返回的是async<bool>而不是bool。我该如何处理Seq.Filter呢?
我应该使用let!将async<bool>转换为bool,然后编写一个非匿名函数来分配返回值吗?
2个回答

2
您可以使用 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.choose过滤掉None值。
要按顺序实现这个功能,你基本上需要自己实现filter,并将其包装在async块中。这将是一个很好的起点(尽管它不是尾递归):
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) }

1
有没有计划将 Seq.FilterAsync 等功能添加到 F# 规范中? - Jamie Dixon

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接