title: Result Builder that accumulates Errors
body: <p>I'm trying to build <code>Result Builder</code> that accumulates <code>Errors</code> (in my case they are named <code>Failures</code> as I'm following some code from <a href="https://fsharpforfunandprofit.com/" rel="nofollow noreferrer">https://fsharpforfunandprofit.com/</a>). It's current implementation returns first encountered <code>Failure</code> when ideally I'd prefer it to either return <code>Success</code> with desired value or a <code>Failure</code> with a list of all missing/corrupted values. Unfortunately current implementation it's a bit verbose.</p>
  <p><strong>Boilerplate code</strong></p>
  <pre><code>module Rop
  
  type RopResult&lt;'TSuccess, 'TMessage&gt; =
      | Success of 'TSuccess * 'TMessage list
      | Failure of 'TMessage list
  
  /// create a Success with no messages
  let succeed x =
      Success (x,[])
  
  /// create a Success with a message
  let succeedWithMsg x msg =
      Success (x,[msg])
  
  /// create a Failure with a message
  let fail msg =
      Failure [msg]
  
  /// A function that applies either fSuccess or fFailure 
  /// depending on the case.
  let either fSuccess fFailure = function
      | Success (x,msgs) -&gt; fSuccess (x,msgs) 
      | Failure errors -&gt; fFailure errors 
  
  /// merge messages with a result
  let mergeMessages msgs result =
      let fSuccess (x,msgs2) = 
          Success (x, msgs @ msgs2) 
      let fFailure errs = 
          Failure (errs @ msgs) 
      either fSuccess fFailure result
  
  /// given a function that generates a new RopResult
  /// apply it only if the result is on the Success branch
  /// merge any existing messages with the new result
  let bindR f result =
      let fSuccess (x,msgs) =
          f x |&gt; mergeMessages msgs
      let fFailure errs =
          Failure errs
      either fSuccess fFailure result
  </code></pre>
  <p><strong>Builder code</strong></p>
  <pre><code>module ResultComputationExpression
      open Rop
      type ResultBuilder() =
          member __.Return(x) = RopResult.Success (x,[])
          member __.Bind(x, f) = bindR f x
  
          member __.ReturnFrom(x) = x
          member this.Zero() = this.Return ()
  
          member __.Delay(f) = f
          member __.Run(f) = f()
  
          member this.While(guard, body) =
              if not (guard()) 
              then this.Zero() 
              else this.Bind( body(), fun () -&gt; 
                  this.While(guard, body))  
  
          member this.TryWith(body, handler) =
              try this.ReturnFrom(body())
              with e -&gt; handler e
  
          member this.TryFinally(body, compensation) =
              try this.ReturnFrom(body())
              finally compensation() 
  
          member this.Using(disposable:#System.IDisposable, body) =
              let body' = fun () -&gt; body disposable
              this.TryFinally(body', fun () -&gt; 
                  match disposable with 
                      | null -&gt; () 
                      | disp -&gt; disp.Dispose())
  
          member this.For(sequence:seq&lt;_&gt;, body) =
              this.Using(sequence.GetEnumerator(),fun enum -&gt; 
                  this.While(enum.MoveNext, 
                      this.Delay(fun () -&gt; body enum.Current)))
  
          member this.Combine (a,b) = 
              this.Bind(a, fun () -&gt; b())
  
      let result = new ResultBuilder()
  </code></pre>
  <p><strong>Use case</strong></p>
  <pre><code>let crateFromPrimitive (taskId:int) (title:string) (startTime:DateTime) : RopResult&lt;SomeValue,DomainErrror&gt; =
      result {
          // functions that, at the end, return &quot;RopResult&lt;TaskID,DomainError&gt;&quot; therefore &quot;let! id&quot; is of type &quot;TaskID&quot;
          let! id = taskId |&gt;  RecurringTaskId.create  |&gt; mapMessagesR mapIntErrors 
          // functions that, at the end, return &quot;RopResult&lt;Title,DomainError&gt;&quot; therefore &quot;let! tt&quot; is of type &quot;Title&quot;
          let! tt = title|&gt; Title.create  |&gt; mapMessagesR mapStringErrors 
          // functions that, at the end, return &quot;RopResult&lt;StartTime,DomainError&gt;&quot; therefore &quot;let! st&quot; is of type &quot;StartTime&quot;
          let! st = startTime|&gt; StartTime.create   |&gt; mapMessagesR mapIntErrors 
          
  
          // &quot;create&quot; returns &quot;RopResult&lt;SomeValue,DomainErrror&gt;&quot;,  &quot;let! value&quot; is of type &quot;SomeValue&quot; 
          let! value = create id tt st 
  
          return value
      }
  </code></pre>
  <p>I could possibly split it to first validate <code>taskId</code>, <code>title</code> and <code>startTime</code> and then eventually call <code>create</code> but is it possible to do in one go?</p>
  <p>I found <a href="https://stackoverflow.com/a/46604411/2710943">this answer</a> but I have no idea how to translate it to my case or if it's even related.</p>
  <p><strong>UPDATE: Solution</strong></p>
  <p>Just like <a href="https://stackoverflow.com/questions/66340678/result-builder-that-accumulates-errors/66344238?noredirect=1#comment117286936_66340678">brainbers</a> comment and <a href="https://stackoverflow.com/a/66344238/2710943">solution</a> says, <code>and!</code> solves my problem. What still troubles me is the idea of automatically de-toupling (namely, when does it happen and on what rules?). In any case, I expect people will be more than able to put two and two together but the working solution for my problem is:</p>
  <p><strong>Builder part</strong></p>
  <pre><code>...
  member _.MergeSources(result1, result2) =
      match result1, result2 with
      | Success (ok1,msgs1), Success (ok2,msgs2) -&gt; 
          Success ((ok1,ok2),msgs1@msgs2 ) 
      | Failure errs1, Success _ -&gt; Failure errs1
      | Success _, Failure errs2 -&gt; Failure errs2
      | Failure errs1, Failure errs2 -&gt; Failure (errs1 @ errs2)   // accumulate errors
  ...
  </code></pre>
  <p><strong>Use Case</strong></p>
  <pre><code>let crateFromPrimitive taskId title startTime duration category description (subtasks:string list option) (repeatFormat:RepeatFormat option) =
      result {
  
          let strintToSubTask = (Subtask.create &gt;&gt; (mapMessagesR mapStringErrors)) 
          let sListToSubtaskList value =  List.map strintToSubTask value
                                            |&gt; RopResultHelpers.sequence
  
          let! id = RecurringTaskId.create taskId |&gt; mapMessagesR mapIntErrors
          and! tt = Title.create title  |&gt; mapMessagesR mapStringErrors
          and! st = StartTime.create startTime  |&gt; mapMessagesR mapIntErrors
          and! dur = Duration.create duration  |&gt; mapMessagesR mapIntErrors
          and! cat = Category.create category  |&gt; mapMessagesR mapStringErrors
          and! desc = Description.create description  |&gt; mapMessagesR mapStringErrors
          and! subtOption = someOrNone sListToSubtaskList subtasks |&gt; RopResultHelpers.fromOptionToSuccess 
          //let! value = create id tt st dur cat desc subtOption repeatFormat
  
          return! create id tt st dur cat desc subtOption repeatFormat
      }
  </code></pre>