组合Async和Option单子



最近在编写一些与许多嵌套异步工作流一起工作的代码时,我发现了一种对我来说很有味道的模式。一个简单的例子:

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 monads,这样它就可以在没有模式匹配的情况下重写。我在想

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开始要求忽略。

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

我没有广泛使用它,但是从我做的一些简单的实验来看,它看起来并没有很好地与f#的其他async功能集成,但如果你想朝这个方向走,ExtCore可能是最好的库。

下面使用AsyncMaybe.Array中的iter函数(来源在这里)。这有点难看,因为我不得不让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函数,然后在其他地方使用它:

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#的伟大之处在于,你可以很容易地自己编写这些抽象,并使它们完全符合你的需求:-)

相关内容

  • 没有找到相关文章

最新更新