How to use nested union types

Hi there!

I’m just starting to get to grips with F# and am hoping to get other devs in my organisation on board too. To that end I’m making some toy applications to understand how everything fits together and I’m hitting a bit of an issue with something like this:

type Base1 = string
type Base2 = int
type Base3 = string

type Int1 =
    | Base1 of Base1
    | Base2 of Base2

type Int2 = 
    | Base3 of Base3

type Top =
    | Int1 of Int1
    | Int2 of Int2

let GetATop (key:string) =
    match key with
    | "key1" -> Base1 "foo"
    | "key2" -> Base2 12
    | _ -> Base3 "bar"

I have some simple base types which are nested into Int1, Int2, which in turn are nested in Top. Ideally the pattern match would return a Top, however the compiler appears to attribute Base1 to being a Int1 and can’t seem to make the jump to it also being a Top. This means that the last case where I return a Base3 results in an error.

So what am I doing wrong here? I think I’ve defined the structure correctly, but it’ll only compile if i do this:

type Base1 = string
type Base2 = int
type Base3 = string

type Top =
    | Base1 of Base1
    | Base2 of Base2
    | Base3 of Base3

let GetATop (key:string) =
    match key with
    | "key1" -> Base1 "foo"
    | "key2" -> Base2 12
    | _ -> Base3 "bar"

Thanks for your help in advance. I really want to make F# work, but I need to understand what I can and can’t do… I can’t seem to find any solid documentation for this use case.

1 Like

Hi Ataxia!

If I understand correctly, you were expecting that by nesting union types you could create a type hierarchy were all types (Base1, Base2, Base3, Int1, Int2) would be subtypes of a super type (Top). The short answer is this is not possible.

While it’s true that union types are often described as a lightweight class hierarchy alternative, this is to be understood in the context of a single union type definition, just like you did in your second code sample. What you are doing in the first code sample should be understood simply as composition of types.

If you want to describe a type hierarchy that looks like your first code sample, you will have to use F# OOP features: define classes and use inheritance.

Not sure I got what are you trying to achieve, but maybe you looking for something like this:

let GetATop (key:string) =
    match key with
    | "key1" -> Base1 "foo" |> Int1
    | "key2" -> Base2 12  |> Int1
    | _ -> Base3 "bar" |> Int2

Ahhh, that makes sense. I’d rather like to limit my use of the oo features and write idiomatic functional F# where possible. Thank you for the explanation!

That’s a cute idea which I didn’t consider. I think i might need to change the approach though. Thank you for your help!

2 Likes