1

最近在编写一些适用于许多嵌套异步工作流的代码时,我发现一种新出现的模式让我感到很不舒服。一个简单的例子:

let flip f x y = f y x
let slowInc x = async {
    do! Async.Sleep 500
    printfn "Here you go, %d" x
}

let verboseFun inp = async {
    match List.tryFind (flip (>) 3) inp with
    | Some x -> do! slowInc x
    | _ -> ()
}

verboseFun [1..5] |> Async.RunSynchronously

'verboseFun' 对我来说似乎很冗长,但我想不出一种方法来组合 Option 和 Async monad,这样就可以在没有模式匹配的情况下重写它。我在想类似的东西

let terseFun inp = async {
    inp
    |> List.tryFind (flip (>) 3)
    |> Option.iterAsync slowInc
}

在我看来,我很可能只是不知道有哪些构建块可以实现这一目标。

编辑:托马斯回答后的额外澄清。

如果一切都是同步的,我试图适应对我来说微不足道的事情,例如,

let terseFun inp =
    inp
    |> List.tryFind (flip (>) 3)
    |> Option.iter someSideEffectFunciton

成为嵌套异步工作流的一部分。最初我在想“只是随便做一个!在那里”所以想出了

let terseFun inp = async {
    inp
    |> List.tryFind (flip (>) 3)
    |> Option.iter (fun x -> async { do! someSideEffectFunciton x })
    |> ignore
}

但它立刻让我觉得不对劲,因为 VS 开始要求忽略。希望这有助于澄清。

4

1 回答 1

2

ExtCore有一堆帮助函数,可以让您处理返回可选值的异步计算,即类型Async<'T option>,它甚至定义了asyncMaybe计算构建器来处理它们。

我没有广泛使用它,但从我做的一些简单实验来看,它似乎没有像它可能的那样与 F# 的其余async功能很好地集成,但如果你想朝这个方向发展,ExtCore 可能是周围最好的图书馆。

以下是使用iter来自AsyncMaybe.Array来源在这里)的功能。这有点难看,因为我必须slowInc是 type Async<unit option>,但它非常接近你的要求:

let slowInc x = async {
    do! Async.Sleep 500
    printfn "Here you go, %d" x
    return Some ()
}

let verboseFun inp = 
  inp 
  |> List.tryFind (fun x -> 3 > x) 
  |> Array.ofSeq
  |> AsyncMaybe.Array.iter slowInc 
  |> Async.Ignore

除此之外,我还删除了您的flip函数,因为这不是 F# 中通常推荐的样式(它往往使代码晦涩难懂)。

也就是说,我认为你并不需要一个完整的 ExtCore 库。仅从您发布的一个示例中很难看出您的一般模式是什么,但是如果您的所有代码片段看起来都与您发布的相似,您可以定义自己的asyncIter函数,然后在其他地方使用它:

let asyncIter f inp = async {
  match inp with 
  | None -> ()
  | Some v -> do! f v }

let verboseFun inp = 
   inp 
   |> List.tryFind (fun x -> x > 3) 
   |> asyncIter slowInc

F# 的伟大之处在于,自己编写这些抽象并制作它们非常容易,以便它们完全符合您的需求:-)

于 2014-08-08T16:04:18.153 回答