簡體   English   中英

結合異步和期權單子

[英]Combine Async and Option monads

最近,在編寫一些可用於許多嵌套異步工作流的代碼時,我發現了一種新興的模式,這種模式對我來說很香。 一個簡單的例子:

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開始要求忽略。 希望這有助於澄清。

ExtCore庫具有一堆幫助函數,可讓您處理返回可選值(即Async<'T option>類型)的Async<'T option>計算,甚至定義asyncMaybe計算生成器以使用它們。

我沒有廣泛使用它,但是從我做過的一些簡單實驗來看,它似乎並沒有像它可能與F#的其余async功能很好地集成在一起,但是如果您朝這個方向發展,ExtCore是可能是周圍最好的圖書館。

以下是使用AsyncMaybe.Arrayiter函數( 源在此處 )。 這有點丑陋,因為我必須使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#的偉大之處在於,自己編寫這些抽象並使它們完全符合您的需求非常容易:-)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM