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谢谢;更新!