title: Pattern Matching on a generic container of a Discriminated Union
body: <p>I have this generic container of values:</p>
  
  <pre><code>open System
  
  type Envelope&lt;'a&gt; = {
      Id : Guid
      ConversationId : Guid
      Created : DateTimeOffset
      Item : 'a }
  </code></pre>
  
  <p>I would like to be able to use <strong>Pattern Matching</strong> on the <code>Item</code>, while still <em>retaining the envelope values</em>.</p>
  
  <p>Ideally, I would like to be able to do something like this:</p>
  
  <pre><code>let format x =
      match x with
      | Envelope (CaseA x) -&gt; // x would be Envelope&lt;RecA&gt;
      | Envelope (CaseB x) -&gt; // x would be Envelope&lt;RecB&gt;
  </code></pre>
  
  <p>However, this doesn't work, so I wonder if there's a way to do something like this?</p>
  
  <p><strong>Further details</strong></p>
  
  <p>Assume that I have these types:</p>
  
  <pre><code>type RecA = { Text : string; Number : int }
  type RecB = { Text : string; Version : Version }
  
  type MyDU = | CaseA of RecA | CaseB of RecB
  </code></pre>
  
  <p>I would like to be able to declare values of the type <code>Envelope&lt;MyDU&gt;</code> and still be able to match on the contained <code>Item</code>.</p>
  
  <p>Perhaps this is going off on the wrong tangent, but I first attempted with a mapping function for envelopes:</p>
  
  <pre><code>let mapEnvelope f x =
      let y = f x.Item
      { Id = x.Id; ConversationId = x.ConversationId; Created = x.Created; Item = y }
  </code></pre>
  
  <p>This function has the signature <code>('a -&gt; 'b) -&gt; Envelope&lt;'a&gt; -&gt; Envelope&lt;'b&gt;</code>, so that looks like something we've seen before.</p>
  
  <p>This enables me to define this Partial Active Pattern:</p>
  
  <pre><code>let (|Envelope|_|) (|ItemPattern|_|) x =
      match x.Item with
      | ItemPattern y -&gt; x |&gt; mapEnvelope (fun _ -&gt; y) |&gt; Some
      | _ -&gt; None
  </code></pre>
  
  <p>and these auxiliary Partial Active Patterns:</p>
  
  <pre><code>let (|CaseA|_|) = function | CaseA x -&gt; x |&gt; Some | _ -&gt; None
  let (|CaseB|_|) = function | CaseB x -&gt; x |&gt; Some | _ -&gt; None
  </code></pre>
  
  <p>With these building blocks, I can write a function like this one:</p>
  
  <pre><code>let formatA (x : Envelope&lt;RecA&gt;) = sprintf "%O: %s: %O" x.Id x.Item.Text x.Item.Number
  let formatB (x : Envelope&lt;RecB&gt;) = sprintf "%O: %s: %O" x.Id x.Item.Text x.Item.Version
  let format x =
      match x with
      | Envelope (|CaseA|_|) y -&gt; y |&gt; formatA
      | Envelope (|CaseB|_|) y -&gt; y |&gt; formatB
      | _ -&gt; ""
  </code></pre>
  
  <p>Notice that in the first case, <code>x</code> is an <code>Envelope&lt;RecA&gt;</code>, which you can see because it's possible to read the value off <code>x.Item.Number</code>. Similarly, in the second case, <code>x</code> is <code>Envelope&lt;RecB&gt;</code>.</p>
  
  <p>Also notice that each case requires access to <code>x.Id</code> from the envelope, which is the reason why I can't just match on <code>x.Item</code> to begin with.</p>
  
  <p>This works, but has the following drawbacks:</p>
  
  <ul>
  <li>I need to define a Partial Active Pattern like <code>(|CaseA|_|)</code> in order to decompose <code>MyDU</code> to <code>CaseA</code>, even though there's already a built-in pattern for that.</li>
  <li>Even though I have a Discriminated Union, the compiler can't tell me if I've forgotten a case, because each of the patterns are Partial Active Patterns.</li>
  </ul>
  
  <p>Is there a better way?</p>