Defining a zip code string I'm following this

let StringOfLengthConstructor&lt;'c&gt; (input:string, length:int, defaultConstructor:string-&gt;'c) =
    match input with
    | null -&gt; None
    | x when x.Length = length -&gt; Some(defaultConstructor(input))
    | _ -&gt; None
type String3 = | String3 of string
let String3 input = StringOfLengthConstructor&lt;String3&gt;(input, 3, String3)    
type String4 = | String4 of string
let String4 input= StringOfLengthConstructor&lt;String4&gt;(input, 4, String4)

type String5 = | String5 of string
let String5 input = StringOfLengthConstructor&lt;String5&gt;(input, 5, String5)
type String6 = | String6 of string
let String6 input = StringOfLengthConstructor&lt;String6&gt;(input,6, String6)


and am trying to make more of these with hopefully less repetition. Can this be done without having to repeat type String3 =| String3 of string followed by this?

let String3 input = StringOfLengthConstructor&lt;String3&gt;(input, 3, String3)  


See all the repetition?  For the purpose of defining a zip code, a US zip code could be defined as

type ZipCode = | Us of String5


or

type ZipCode = | Us of String5*(String4 option) | Canadian of String3*String3
The solution can be made cleaner by re-arranging the order of the arguments and using pointfree style.

let StringOfLengthConstructor&lt;'c&gt; (length : int) (defaultConstructor : string -&gt; 'c) (input : string) =
    match input with
    | x when x &lt;&gt; null &amp;&amp; x.Length = length -&gt; Some (defaultConstructor input)
    | _ -&gt; None

type String3 = String3 of string
let String3 = StringOfLengthConstructor 3 String3


However, I don't think that String5 * (String4 option) is a good definition of a zip code. The code should be validating on more than just the string length.