当我使用Hopac创建带有Alt.<functions>的Alt<unit>时,就像总是或一次一样,它会导致奇怪的否定确认结果。
但是,如果我使用async {<expression>}创建Alt<unit>,那么一切都会按预期进行。
open Hopac
open Hopac.Core
open Hopac.Infixes
open Hopac.Extensions
let pf m (s:int) = Alt.prepareFun <| fun _ ->
Alt.always () ^=> fun _ ->
job {
printfn "starting [%s] %d" m Thread.CurrentThread.ManagedThreadId
Thread.Sleep s
printfn "%s" m }
|> Job.start
let delayedPrintn3 msg delayInMillis =
Alt.prepareFun <| fun _ ->
async {
printfn "starting [%s] %d" msg Thread.CurrentThread.ManagedThreadId
do! Async.Sleep delayInMillis
}
|> Alt.fromAsync
|> Alt.afterFun (fun _ -> printfn "%s" msg)
let na : (string -> int -> Alt<unit>) -> string -> string -> int -> Alt<unit> = fun ff s1 s2 i ->
Alt.withNackJob <|
fun nack ->
nack
|> Alt.afterFun (fun () ->
printfn "%s" s1)
|> Job.start
|> Job.map (fun _ -> ff s2 i)
let na11 = na delayedPrintn3 "1 canceled!!" "na11" 3
let na22 = na delayedPrintn3 "2 canceled!!" "na22" 0
let na33 = na pf "1 canceled!!" "na33" 3
let na44 = na pf "2 canceled!!" "na44" 0
na22 <|> na11 |> run
na33 <|> na44 |> run结果是:
starting [na22] 18
starting [na11] 18
na22
1 canceled!!和
starting [na33] 11
na33然而,我希望得到相同的结果。使用Alt.<function>时有什么问题
发布于 2019-09-17 01:42:44
Hopac Alt是非常棘手的,我花了一段时间才把它们弄对。
当您将Alt返回到prepareFun/prepareJob时,您将需要返回一个尚未提交的Alt。在您的pf示例中,您返回的是Alt.always,这意味着此Alt将始终被提交。因此,当调用na33 <|> na44 |> run时,这意味着na33已经被提交,不需要运行na44。
相比之下,delayedPrintn3的示例使用了Async,如果您查看来自https://github.com/Hopac/Hopac/blob/master/Docs/Alternatives.md的参考实现
open System.Threading
let asyncAsAlt (xA: Async<'x>) : Alt<'x> = Alt.withNackJob <| fun nack ->
let rI = IVar ()
let tokenSource = new CancellationTokenSource ()
let dispose () =
tokenSource.Dispose ()
// printfn "Dispose"
let op = async {
try
let! x = xA
do rI *<= x |> start
// do printfn "Success"
with e ->
do rI *<=! e |> start
// do printfn "Failure"
}
Async.Start (op, cancellationToken = tokenSource.Token)
nack
>>- fun () ->
tokenSource.Cancel ()
// printfn "Cancel"
dispose ()
|> Job.start >>-.
Alt.tryFinallyFun rI dispose它正在创建一个IVar (将它们视为与TaskCompletionSource相同),稍后将在启动异步op后设置它。所以在你的例子中,你可以看到它们都是启动的,因为它们的IVar还没有被提交。
如果您正在寻找类似的实现,则如下所示:
let pf2 m (s:int) = Alt.prepareJob <| fun _ ->
let retVal = IVar<unit>()
job {
printfn "starting [%s] %d" m Thread.CurrentThread.ManagedThreadId
do! timeOutMillis s
printfn "%s" m
do! IVar.fill retVal ()
}
|> Job.start
>>-. retVal它返回一个尚未提交的IVar (这是一个Alt)。我不得不将睡眠时间提高到100,以确保Hopac不会太快地完成第一个任务。
let na55 = na pf2 "1 canceled!!" "na55" 100
let na66 = na pf2 "2 canceled!!" "na66" 0starting [na55] 9
starting [na66] 9
na66
1 canceled!!https://stackoverflow.com/questions/57956469
复制相似问题