结合Async和Option monads

时间:2014-08-08 15:44:58

标签: asynchronous f# monads monad-transformers async-workflow

在编写一些适用于大量嵌套异步工作流程的代码时,我发现了一种让我闻起来的模式。一个简单的例子:

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开始要求忽视。 希望这有助于澄清。

1 个答案:

答案 0 :(得分:2)

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

我没有广泛使用它,但是从我做过的一些简单的实验来看,它看起来并不像其他F#的async功能那样很好地集成,但是如果你想朝着这个方向前进,ExtCore可能是最好的图书馆。

以下是使用itersource 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#的好处是,自己编写这些抽象并使它们完全符合您的需求非常容易: - )