F# 如何实现Task.Map
我是否正确执行了F# 如何实现Task.Map,f#,c#-to-f#,F#,C# To F#,我是否正确执行了任务的映射 let map continuation (t: Task<'A>) = t.ContinueWith(fun (antecedent: Task<'A>) -> if antecedent.Status <> TaskStatus.Canceled && antecedent.Status <> TaskStatus.Faulted then
任务
的映射
let map continuation (t: Task<'A>) =
t.ContinueWith(fun (antecedent: Task<'A>) ->
if antecedent.Status <> TaskStatus.Canceled &&
antecedent.Status <> TaskStatus.Faulted then
continuation antecedent.Result
else
raise antecedent.Exception // must I?
)
let map continuation(t:Task)->
如果为antecedent.Status任务状态。已取消&&
antecedent.Status TaskStatus.Faulted then
延续先行结果
其他的
引发先行项。异常//我必须吗?
)
我从中获得了TaskStatus
检查。我觉得最不确定的是提出先行项.Exception
,但我想不出其他方法来处理它
作为背景,是的,我知道
Async
,但我当前的堆栈使用实体框架和Blazor,所以我有一个后端,使用.ToListAsync()
和一个前端C#,因此,我宁愿不要处理从任务
到异步
再转换回来的问题。在继续中再次抛出异常将导致错误的堆栈跟踪。
它是从'a->'B
映射而来的,因此最好明确地对其进行布局
let rec map (continuation: 'A -> 'B) (t: Task<'A>) =
let rec map_resolved (task: Task<'A>) =
match task.Status with
| TaskStatus.RanToCompletion -> Task.FromResult(continuation task.Result)
| TaskStatus.Faulted -> Task.FromException<'B>(task.Exception)
| TaskStatus.Canceled -> Task.FromCanceled<'B>(CancellationToken.None)
| _ -> task.ContinueWith(map_resolved).Unwrap()
map_resolved t
let rec map(续:“A->”B)(t:Task)=
将任务状态与匹配
|TaskStatus.RanToCompletion->Task.FromResult(continuation Task.Result)
|TaskStatus.Faulted->Task.FromException(CancellationToken.None)
|->task.ContinueWith(已解析映射)。Unwrap()
地图
我建议根据TPL中可等待的概念背后的接口实施您的解决方案,即INotifyCompletion
和ICriticalNotifyCompletion
。另外,要正确实现map
,您应该真正使用bind
。在F#中已经有了一些现有的解决方案,例如库。就我个人而言,我多年来一直在图书馆使用以下内容,没有任何问题:
open System.Runtime.CompilerServices
open System.Threading.Tasks
type TaskStep<'result> =
| Value of 'result
| AsyncValue of 'result Task
| Continuation of ICriticalNotifyCompletion * (unit -> 'result TaskStep)
and StateMachine<'a>(firstStep) as this =
let methodBuilder = AsyncTaskMethodBuilder<'a Task>()
let mutable continuation = fun () -> firstStep
let nextAwaitable() =
try
match continuation() with
| Value r ->
methodBuilder.SetResult(Task.FromResult(r))
null
| AsyncValue t ->
methodBuilder.SetResult(t)
null
| Continuation (await, next) ->
continuation <- next
await
with
| exn ->
methodBuilder.SetException(exn)
null
let mutable self = this
member __.Run() =
methodBuilder.Start(&self)
methodBuilder.Task
interface IAsyncStateMachine with
member __.MoveNext() =
let mutable await = nextAwaitable()
if not (isNull await) then
methodBuilder.AwaitUnsafeOnCompleted(&await, &self)
member __.SetStateMachine(_) =
()
type Binder<'out> =
static member inline GenericAwait< ^abl, ^awt, ^inp
when ^abl : (member GetAwaiter : unit -> ^awt)
and ^awt :> ICriticalNotifyCompletion
and ^awt : (member get_IsCompleted : unit -> bool)
and ^awt : (member GetResult : unit -> ^inp) >
(abl : ^abl, continuation : ^inp -> 'out TaskStep) : 'out TaskStep =
let awt = (^abl : (member GetAwaiter : unit -> ^awt)(abl))
if (^awt : (member get_IsCompleted : unit -> bool)(awt))
then continuation (^awt : (member GetResult : unit -> ^inp)(awt))
else Continuation (awt, fun () -> continuation (^awt : (member GetResult : unit -> ^inp)(awt)))
module TaskStep =
let inline bind f step : TaskStep<'a> =
Binder<'a>.GenericAwait(step, f)
let inline toTask (step: TaskStep<'a>) =
try
match step with
| Value x -> Task.FromResult(x)
| AsyncValue t -> t
| Continuation _ as step -> StateMachine<'a>(step).Run().Unwrap()
with
| exn ->
let src = new TaskCompletionSource<_>()
src.SetException(exn)
src.Task
module Task =
let inline bind f task : Task<'a> =
TaskStep.bind f task |> TaskStep.toTask
let inline map f task : Task<'b> =
bind (f >> Value) task
open System.Runtime.CompilerServices
开放系统.Threading.Tasks
键入TaskStep()
让可变延续=fun()->第一步
让我们来看看nextAwaitable()=
尝试
将continuation()与
|值r->
methodBuilder.SetResult(Task.FromResult(r))
无效的
|异步值t->
methodBuilder.SetResult(t)
无效的
|继续(等待,下一步)->
延续
methodBuilder.SetException(exn)
无效的
让可变自我=这个
成员_u.Run()=
methodBuilder.Start(&self)
methodBuilder.任务
IAsyncStateMachine与的接口
成员_uu.MoveNext()=
让可变等待=nextAwaitable()
如果不是(isNull等待),则
methodBuilder.await未安全完成(&await,&self)
成员uuu.SetStateMachine(uu)=
()
活页夹=
活页夹)=
尝试
步调一致
|值x->Task.FromResult(x)
|异步值t->t
|继续作为步骤->状态机=
TaskStep.bind f task |>TaskStep.toTask
让内联映射f task:task实现它。我将在下面粘贴当前版本,因为它很短。它使用前面提到的Aaron
module Task =
let singleton value = value |> Task.FromResult
let bind (f : 'a -> Task<'b>) (x : Task<'a>) = task {
let! x = x
return! f x
}
let map f x = x |> bind (f >> singleton)
模块任务=
让singleton value=value |>Task.FromResult
让我们绑定(f:'a->Task)=Task{
设!x=x
返回!fx
}
让映射fx=x |>绑定(f>>单态)
此外,还有一个独立的Task.map实现
你能更新你的答案吗?F#+最新版本。而且它不依赖taskbuilder。@Gus谢谢;更新!