7 people like it.

Enforcing business rules

A simple example of how to define a custom type that enforces extra business rules by using a single-case discriminated union with a private constructor

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
22: 
23: 
24: 
25: 
type Person = 
  { Name : string
    Age : int }

module CheckedPerson = 
  type CheckedPerson = 
    private | CP of Person
    member x.Person = let (CP p) = x in p
    static member Create(p:Person) = 
      if p.Name = "Yoda" then Some (CP p)
      elif p.Age < 100 then Some (CP p)
      else None

open CheckedPerson

// CP is not publicly accessible; we cannot 
// create CheckedPerson directly
CP { Name = "Tomas"; Age = 999 }

// This compiles, but returns None
CheckedPerson.Create { Name = "Tomas"; Age = 999 }

// This works, extra business rules satisfied
CheckedPerson.Create { Name = "Tomas"; Age = 99 }
CheckedPerson.Create { Name = "Yoda"; Age = 700 }
Person.Name: string
Multiple items
val string : value:'T -> string

--------------------
type string = System.String
Person.Age: int
Multiple items
val int : value:'T -> int (requires member op_Explicit)

--------------------
type int = int32

--------------------
type int<'Measure> = int
union case CheckedPerson.CP: Person -> CheckedPerson
type Person =
  { Name: string
    Age: int }
val x : CheckedPerson
val p : Person
union case Option.Some: Value: 'T -> Option<'T>
union case Option.None: Option<'T>
module CheckedPerson

from Script
Multiple items
module CheckedPerson

from Script

--------------------
type CheckedPerson =
  private | CP of Person
    member Person : Person
    static member Create : p:Person -> CheckedPerson option
static member CheckedPerson.Create : p:Person -> CheckedPerson option
Raw view Test code New version

More information

Link:http://fssnip.net/7ZK
Posted:4 years ago
Author:Tomas Petricek
Tags: discriminated union