Skip to content

BUG : Task Monad is not abide associativity low when one of the results is error #362

Description

@baio

Description

Task Monad is not abide associativity low when one of the results is error

Repro steps

open FSharpx.Task

[<Test>]
let ``For Task monad associativity low must work even if some result contains error`` () =
    
    let am x = returnM x
    let bm x = returnM x
    let cm _ = Task.FromException<int> (exn "error")

    let l = am >=> bm >=> cm
    let r = bm >=> cm >=> am

    let rl = run (fun () -> l 1)
    let rr = run (fun () -> r 1)

    //Assert.Equal(rl, rr)
     // Dunno how to compare object instances in F# correctly 

    match (rl, rr) with
        | Error e1, Error e2 ->
           // Will fail
           Assert.Equal(e1.InnerException.Message, e2.InnerException.Message)
        | _ -> Assert.True(false)```

Expected behavior

    let l = am >=> bm >=> cm
    let r = bm >=> cm >=> am

Left and right results must be the same.

Actual behavior

They are not, since

    let inline bind (f: 'T -> Task<'U>) (m: Task<'T>) = 
        m.ContinueWith(fun (x: Task<_>) -> f x.Result).Unwrap()

implemented incorrectly, when x.Result will be invoked for task with error, it will throw new exception since x.Result doesn't have value. From example above r value indeed will have following exception
Exception inside AggregatedException inside AggregatedException. Every bind down the flow will stack up another aggregated exception to the error.

Known workarounds

let  bind (f: _ -> Task<_>) (x: Task<_>) = 
    x.ContinueWith(fun (t: Task<_>) -> 
        if t.IsFaulted then Task.FromException<_>(t.Exception.InnerException) else f t.Result 
    ) .Unwrap()

Related information

Probably this behavior is incorrect also for map and similar operators. Also possible the same situation when Task has canceled result

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions