title: How to keep the stacktrace when rethrowing an exception out of catch-context?
body: <p>TL;DR: how to raise a previously caught exception later on, while preserving the original exception's stacktrace.</p>
  
  <p>Since I think this is useful with the <code>Result</code> monad or computation expression, esp. since that pattern is often used for wrapping an exception without throwing it, here's a worked out example of that:</p>
  
  <pre><code>type Result&lt;'TResult, 'TError&gt; =
      | Success of 'TResult
      | Fail of 'TError
  
  module Result =
      let bind f = 
          function
          | Success v -&gt; f v
          | Fail e -&gt; Fail e
  
      let create v = Success v
  
      let retnFrom v = v
  
      type ResultBuilder () =
          member __.Bind (m , f) = bind f m
          member __.Return (v) = create v
          member __.ReturnFrom (v) = retnFrom v
          member __.Delay (f) = f
          member __.Run (f) = f()
          member __.TryWith (body, handler) =
              try __.Run body
              with e -&gt; handler e
  
  [&lt;AutoOpen&gt;]
  module ResultBuilder =
      let result = Result.ResultBuilder()
  </code></pre>
  
  <p>And now let's use it:</p>
  
  <pre><code>module Extern =
      let calc x y = x / y
  
  
  module TestRes =
      let testme() =
          result {
              let (x, y) = 10, 0
              try
                  return Extern.calc x y
              with e -&gt; 
                  return! Fail e
          }
          |&gt; function
          | Success v -&gt; v
          | Fail ex -&gt; raise ex  // want to preserve original exn's stacktrace here
  </code></pre>
  
  <p>The problem is that the stacktrace will <em>not include the source of the exception</em> (here namely the <code>calc</code> function). If I run the code as written, it will throw as follows, which gives no information to the origin of the error:</p>
  
  <pre class="lang-none prettyprint-override"><code>System.DivideByZeroException : Attempted to divide by zero.
     at Microsoft.FSharp.Core.Operators.Raise[T](Exception exn)
     at PlayFul.TestRes.testme() in D:\Experiments\Play.fs:line 197
     at PlayFul.Tests.TryItOut() in D:\Experiments\Play.fs:line 203
  </code></pre>
  
  <p>Using <code>reraise()</code> won't work, it wants a catch-context. Obviously, the following kind-a works, but makes debugging harder because of the nested exceptions and could get pretty ugly if this wrap-reraise-wrap-reraise pattern gets called multiple times in a deep stack.</p>
  
  <pre><code>System.Exception("Oops", ex)
  |&gt; raise
  </code></pre>
  
  <p>Update: TeaDrivenDev suggested in the comments to use <code>ExceptionDispatchInfo.Capture(ex).Throw()</code>, which works, but requires to wrap the exception in something else, complicating the model. However, it does preserve the stacktrace and it can be made into a fairly workable solution.</p>