Records

type Person = {
    Name: string
    Age: int
    Email: string option
}

let ana = { Name = "Ana"; Age = 30; Email = Some "[email protected]" }   // type inferred from the labels
let older = { ana with Age = 31 }                                 // copy-and-update (immutable)
ana.Name                                                          // "Ana"
ana = { Name = "Ana"; Age = 30; Email = Some "[email protected]" }        // true: structural equality
let sorted = [ older; ana ] |> List.sortBy _.Age                  // structural comparison also available

// Deconstruction in patterns
let describe { Name = n; Age = a } = $"{n} ({a})"

// Records with members
type Point =
    { X: float; Y: float }
    member this.Length = sqrt (this.X * this.X + this.Y * this.Y)
    static member Origin = { X = 0.0; Y = 0.0 }
    static member (+) (a: Point, b: Point) = { X = a.X + b.X; Y = a.Y + b.Y }

let p = { X = 3.0; Y = 4.0 }
p.Length                                   // 5.0
p + Point.Origin

// Anonymous records (no type declaration)
let config = {| Host = "localhost"; Port = 8080 |}
config.Port                                // 8080
let extended = {| config with Debug = true |}

// Struct records
[<Struct>
…