Firstly, one very important thing: when you write
type B_Parent = A | B
you are not declaring that B_Parent is a DU connecting the two previously defined types A and B There is no syntax for this.
What the line actually does is define two empty B_Parent subtypes that have nothing to do with the original A and B This is equivalent to:
type B_Parent = B_Parent.A | B_Parent.B
To reuse existing types inside a DU, you need to specify a name for the case β effectively wrap them with another type. So the correct declaration might be something like this:
type B_Parent = P_a of A | P_b of B
With this in mind, as Anton said, the and keyword is the key to defining reciprocal reference types. However, it is best to keep such reciprocal links as small and dense as possible. Therefore, we could do something like this:
type A = { parent:A_Parent; ... } and A_Parent = P_a of A | None type B = { parent:B_Parent; ... } and B_Parent = P_a of A | P_b of B type C = { parent:C_Parent; ... } and C_Parent = P_a of A type D = { parent:D_Parent; ... } and D_Parent = P_b of B | P_c of C | P_d of D
We could use only the A option for A_Parent and just A for C_Parent , but I think that keeping matches in file names will probably make reading more understandable.
source share