I have some problems to use "with" with a discriminated union:
type NaturalPerson = {
FirstName: string
LastName: string
}
type CorporateEntity = {
Name1: string
Name2: string option
}
type Person =
| Natural of NaturalPerson
| Company of CorporateEntity
let company = Company { Name1 = "Foo Bar AG"; Name2 = Some "Baz" }
Now I want to change Name2 to None, but I could not figure out how. Something like:
let company2 = Company { company with Name2 = None }
In my "real world example" of course this is nested, otherwise I could use the correct type.
Maybe this isn't possible, because I have to pattern match for an edge case, that can not exist (but the compiler is not smart enough to know).
If you break it out a bit more it is easier to see the problem. In fact what is probably making this difficult is the naming.
let company = Company { Name1 = "Foo Bar AG"; Name2 = Some "Baz" } // Person
let company2 = Company { company with Name2 = None } // Person, but broken because expecting company to be type of CorporateEntity
So you are trying to create a CorporateEntity
with a Person
type, which are not the same.
This works because the correct type is used.
let c1 : CorporateEntity = { Name1 = "Foo Bar AG"; Name2 = Some "Baz" }
let p1 : Person = Company c1
let c2 : CorporateEntity = { c1 with Name2 = None }
let p2 : Person = Company c2
I have added the types and changed the name to make the type more apparent.
You could match
on this...
match company with // <- rename company to person so it is clearer
| Natural _ -> company
| Company c -> Company { c with Name2 = None }
If you wanted to match in a function you could do it like this:
let noCompanyName2 (c:CorporateEntity) = // c:CorporateEntity -> Person
let { Name1 = n1; Name2 = _ } = c
let company3 = Company { Name1 = n1; Name2 = None }
company3
Or more concisely:
let noCompanyName2 ({ Name1 = n1; Name2 = _ }) = Company { Name1 = n1; Name2 = None }
Hope this helps.