Discriminated Union - Allow Pattern Matching but Restrict Construction : <p>I have an F# Discriminated Union, where I want to apply some "constructor logic" to any values used in constructing the union cases.  Let's say the union looks like this:</p>

<pre><code>type ValidValue =
| ValidInt of int
| ValidString of string
// other cases, etc.
</code></pre>

<p>Now, I want to apply some logic to the values that are actually passed-in to ensure that they are valid.  In order to make sure I don't end up dealing with <code>ValidValue</code> instances that aren't really valid (haven't been constructed using the validation logic), I make the constructors private and expose a public function that enforces my logic to construct them.</p>

<pre><code>type ValidValue = 
    private
    | ValidInt of int
    | ValidString of string

module ValidValue =
    let createInt value =
        if value &gt; 0 // Here's some validation logic
        then Ok &lt;| ValidInt value
        else Error "Integer values must be positive"

    let createString value =
        if value |&gt; String.length &gt; 0 // More validation logic
        then Ok &lt;| ValidString value
        else Error "String values must not be empty"
</code></pre>

<p>This works, allowing me to enforce the validation logic and make sure every instance of <code>ValidValue</code> really is valid.  However, the problem is that no one outside of this module can pattern-match on <code>ValidValue</code> to inspect the  result, limiting the usefulness of the Discriminated Union.  </p>

<p>I would like to allow outside users to still pattern-match and work with the <code>ValidValue</code> like any other DU, but that's not possible if it has a private constructor.  The only solution I can think of would be to wrap each value inside the DU in a single-case union type with a private constructor, and leave the actual <code>ValidValue</code> constructors public.  This would expose the cases to the outside, allowing them to be matched against, but still mostly-prevent the outside caller from constructing them, because the values required to instantiate each case would have private constructors:</p>

<pre><code>type VInt = private VInt of int
type VString = private VString of string

type ValidValue = 
| ValidInt of VInt
| ValidString of VString

module ValidValue =
    let createInt value =
        if value &gt; 0 // Here's some validation logic
        then Ok &lt;| ValidInt (VInt value)
        else Error "Integer values must be positive"

    let createString value =
        if value |&gt; String.length &gt; 0 // More validation logic
        then Ok &lt;| ValidString (VString value)
        else Error "String values must not be empty"
</code></pre>

<p>Now the caller can match against the cases of <code>ValidValue</code>, but they can't read the actual integer and string values inside the union cases, because they're wrapped in types that have private constructors.  This can be fixed with <code>value</code> functions for each type:</p>

<pre><code>module VInt =
    let value (VInt i) = i

module VString =
    let value (VString s) = s
</code></pre>

<p>Unfortunately, now the burden on the caller is increased:</p>

<pre><code>// Example Caller
let result = ValidValue.createInt 3

match result with
| Ok validValue -&gt;
    match validValue with
    | ValidInt vi -&gt;
        let i = vi |&gt; VInt.value // Caller always needs this extra line
        printfn "Int: %d" i
    | ValidString vs -&gt;
        let s = vs |&gt; VString.value // Can't use the value directly
        printfn "String: %s" s
| Error error -&gt;
    printfn "Invalid: %s" error
</code></pre>

<p>Is there a better way to enforce the execution of the constructor logic I wanted at the beginning, without increasing the burden somewhere else down the line?</p>
