问题描述
假设我想在 async
工作流中返回一个 Option
:
Say i want to return an Option
while in an async
workflow:
let run =
async {
let! x = doAsyncThing
let! y = doNextAsyncThing x
match y with
| None -> return None
| Some z -> return Some <| f z
}
理想情况下,我会在异步的同时使用来自 FSharpx 的可能计算表达式,以避免执行 match
.我可以制作一个自定义构建器,但是有没有办法将两个计算表达式一般地组合起来?它可能看起来像这样:
Ideally I would use the maybe computation expression from FSharpx at the same time as async to avoid doing the match
. I could make a custom builder, but is there a way to generically combine two computation expressions? It might look something like this:
let run =
async {
let! x = doAsyncThing
let! y = doNextAsyncThing x
return! f y
}
推荐答案
通常在 F# 中,您手动定义工作流而不是使用通用工作流,或者使用现成可用的工作流async
和 可能
但如果您想将它们结合使用,则需要手动编写特定的工作流组合.
Typically in F# instead of using generic workflows you define the workflow by hand, or use one that is ready available as in your case async
and maybe
but if you want to use them combined you will need to code a specific workflow combination by hand.
或者,您可以使用 F#+,这是一个为以下项目提供通用工作流程的项目monads,在这种情况下,它将自动为您派生,这是一个工作示例,使用您的工作流程,然后使用 OptionT
这是一个 monad 转换器:
Alternatively you can use F#+ which is a project that provides generic workflows for monads, in that case it will be automatically derived for you, here's a working example, using your workflow and then using OptionT
which is a monad transformer:
#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 中.
The first function has to be 'lifted' into the other monad, because it only deals with Async
(not with Option
), the second function deals with both so it only needs to be 'packed' into our OptionT
DU.
正如您所看到的,两个工作流都是自动派生的,一个是您拥有的(异步工作流),另一个是您想要的.
As you can see both workflows are derived automatically, the one you had (the async workflow) and the one you want.
有关此方法的更多信息,请阅读Monad Transformers.
For more information about this approach read about Monad Transformers.
这篇关于结合 F# 异步和计算表达式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!