通常在 F# 中,您不是使用通用工作流,而是手动定义工作流,或者使用在您的情况下可用的工作流,async
但是maybe
如果您想组合使用它们,则需要手动编写特定的工作流组合。
或者,您可以使用F#+,这是一个为 monad 提供通用工作流程的项目,在这种情况下,它将自动为您派生,这是一个工作示例,使用您的工作流程,然后使用OptionT
哪个是 monad 转换器:
#r "nuget: FSharpPlus, 1.2"
open FSharpPlus
open FSharpPlus.Data
let doAsyncThing = async {return System.DateTime.Now}
let doNextAsyncThing (x:System.DateTime) = async {
let m = x.Millisecond
return (if m < 500 then Some m else None)}
let f x = 2 * x
// then you can use Async<_> (same as your code)
let run = monad {
let! x = doAsyncThing
let! y = doNextAsyncThing x
match y with
| None -> return None
| Some z -> return Some <| f z}
let res = Async.RunSynchronously run
// or you can use OptionT<Async<_>> (monad transformer)
let run' = monad {
let! x = lift doAsyncThing
let! y = OptionT (doNextAsyncThing x)
return f y}
let res' = run' |> OptionT.run |> Async.RunSynchronously
第一个函数必须“提升”到另一个 monad,因为它只处理Async
(而不是Option
),第二个函数处理两者,所以它只需要被“打包”到我们的OptionT
DU 中。
如您所见,两个工作流都是自动派生的,一个是您拥有的(异步工作流),另一个是您想要的。
有关此方法的更多信息,请阅读Monad Transformers。