F# makes it easy to model a domain with discriminated unions (= it is one of these values) and measures (type-safe numbers). Excerpt from our expenses sub-system:
* in a type definition stands for a tuple:
int * string is a tuple of an int and a string, like
42, "this is a tuple". The definition uses a
*, the values a
Single-case discriminated unions like
type DimensionId = DimensionId of Guid are a simple way of making basic types type-safe. There is an alternative: using FSharp.UMX allows using measures on GUIDs (I’ll post an example later).
Normal discriminated unions are great for expressing that a value is either this or that:
type MyDiscriminatedUnion = | This | That of MyData: string
And you can add data to the cases.
And, of course, all these types are immutable and support structural comparison out of the box.