Handling bill cancellation I'm trying to refactor the working code below which intends to handle bill cancellation, but doesn't seem &quot;linear&quot; enough.
open FSharpPlus
open FSharpPlus.Data

type BillCancellationReason = | A | B
type OrderBillingCommand = | A | B
type OrderBillingEvent = | A | B
type CommandError = | A | B

type BillCancellationRequest =
    { BillSequence: int32
      Reason: BillCancellationReason
      Comment: string }

type BillCancellationsRequestPart =
    { OrderId: int32
      BillSequence: int32
      Reason: BillCancellationReason
      Comment: string }

type BillCancellationsRequest = BillCancellationsRequestPart list

module Validation =
    // Validation&lt;'Failure list, 'Success&gt; list -&gt; Validation&lt;'Failure list, 'Success list&gt;
    let cumulativeFoldList (validations: Validation&lt;'Failure list, 'Success&gt; list):
        Validation&lt;'Failure list, 'Success list&gt; =
        traverse id validations

// BillCancellationsRequestPart -&gt; Validation&lt;CommandError list, (int32 * OrderBillingCommand)&gt;
let toCommand (requestPart: BillCancellationsRequestPart) =
    Unchecked.defaultof&lt;Validation&lt;CommandError list, (int32 * OrderBillingCommand)&gt;&gt;

// (int32 * OrderBillingCommand) list -&gt; Async&lt;Result&lt;OrderBillingEvent list, CommandError list&gt;&gt;
let processValidCommands (commands: (int32 * OrderBillingCommand) list) =
    Unchecked.defaultof&lt;Async&lt;Result&lt;OrderBillingEvent list, CommandError list&gt;&gt;&gt;

// BillCancellationsRequest -&gt; Async&lt;Result&lt;OrderBillingEvent list,CommandError list&gt;&gt;
let cancelBills (request: BillCancellationsRequest) =
    async {
        match request |&gt; List.map toCommand |&gt; Validation.cumulativeFoldList with
        | Success commands -&gt; return! processValidCommands commands
        | Failure failure -&gt; return Error failure
    }

In particular this last bit:
// BillCancellationsRequest -&gt; Async&lt;Result&lt;OrderBillingEvent list,CommandError list&gt;&gt;
let cancelBills (request: BillCancellationsRequest) =
    async {
        match request |&gt; List.map toCommand |&gt; Validation.cumulativeFoldList with
        | Success commands -&gt; return! processValidCommands commands
        | Failure failure -&gt; return Error failure
    }

I tried to come up with a new module but I found myself rolling a lot more code:

module Result =
    // ('T -&gt; 'U) -&gt; ('V -&gt; 'W) -&gt; Result&lt;'T, 'V&gt; -&gt; Result&lt;'U, 'W&gt;
    let bimap okMapping errorMapping result =
        result
        |&gt; Result.map okMapping
        |&gt; Result.mapError errorMapping

    // Result&lt;Async&lt;'T&gt;, 'U&gt; -&gt; Async&lt;Result&lt;'T, 'U&gt;&gt;
    let awaitOnOk result =
        async {
            match result with
            | Ok ok -&gt;
                let! awaitedOk = ok
                return Ok awaitedOk
            | Error error -&gt;
                return Error error
        }

// BillCancellationsRequest -&gt; Async&lt;Result&lt;OrderBillingEvent list,CommandError list&gt;&gt;
let cancelBills (request: BillCancellationsRequest) =
    request
    |&gt; List.map toCommand
    |&gt; Validation.cumulativeFoldList
    |&gt; Validation.toResult
    |&gt; Result.map processValidCommands
    |&gt; Result.awaitOnOk
    |&gt; Async.map Result.flatten

I'm wondering if there is like a better and more concise approach to achieve that?
Note: Unchecked.defaultof&lt;...&gt; has been used just for the sake of making the code above to compile.
To be honest, your original implementation of cancelBills looks pretty good - it's very focused and is fairly easy to understand what it's doing even without much context.
If you really want to write the function as a single chain of functions then your alternative version is most of the way there. I'd consider replacing the last three functions in the chain with a single Result.asyncBind function to simplify it somewhat, i.e.
module Result  =
    let asyncBind (asyncBinder: 'T -&gt; Async&lt;Result&lt;'U, 'TError&gt;&gt;) (result: Result&lt;'T, 'TError&gt;) =
        match result with
        | Result.Ok value -&gt; asyncBinder value
        | Result.Error error -&gt; async { return Result.Error error }

This is effectively just an async equivalent of the built-in Result.bind, so shouldn't add much overhead when reading the code and should be fairly re-usable if you're piping Result and Async around a lot. That being said, if you're not going to be re-using Result.asyncBind (or your equivalent function chain) then just stick with your original implementation of cancelBills!