在编写一些适用于大量嵌套异步工作流程的代码时,我发现了一种让我闻起来的模式。一个简单的例子:
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
}
在我看来,我很可能不知道有哪些构建模块可以实现这一点。
编辑:Tomas'之后的额外澄清答案。
如果一切都是同步的,我试图调整对我来说微不足道的东西,例如,
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开始要求忽视。 希望这有助于澄清。
答案 0 :(得分:2)
ExtCore library有一堆辅助函数,可以让你处理返回可选值的异步计算,即类型Async<'T option>
,它甚至定义asyncMaybe
计算构建器来处理它们
我没有广泛使用它,但是从我做过的一些简单的实验来看,它看起来并不像其他F#的async
功能那样很好地集成,但是如果你想朝着这个方向前进,ExtCore可能是最好的图书馆。
以下是使用iter
(source is here)中的AsyncMaybe.Array
功能。这有点难看,因为我必须使slowInc
属于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
函数,然后在别处使用它: / p>
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#的好处是,自己编写这些抽象并使它们完全符合您的需求非常容易: - )