Search code examples
arraysf#discriminated-union

Getting a typed array from a discriminate union of different types of arrays in F#


If I have a discriminate union of different types of arrays how can i convert them to their 'actual' types?

type ItemStuff = 
   | Colors of string[]
   | Sizes of int[]

let foo = Sizes [|1;2;3|]

After running the above when I get the value of foo I see:

val foo : ItemStuff = Sizes [|1;2;3|]

How can I get an actual array of int's from foo? Am I just missing some syntax that allows me access to something like foo.[2]? I cannot enumerate through foo so I wasn't able to use map. I could write a member for ItemStuff that returns a properly typed array for each different type of array i am returning, but that just didn't seem right?

What are my best approaches here?

Here is what I ended up doing. any ideas on better ways to do it?

type ItemProp =
| Colors of string[]
| Sizes of int[]
| Quants of int[]
member this.GetColors() =
   match this with
   | Colors (stringArray) ->
       stringArray
   | _ -> null
member this.GetIntArr() =
   match this with
   | Sizes (intArray) | Quants (intArray) ->
       intArray
   |_ -> null

foo.GetIntArr()

Solution

  • How can I get an actual array of int's from foo?

    That's the actual problem since foo is just said to have type ItemStuff. So it doesn't have to contain a Sizes-value at all - it could be a Colors as well.

    Hence your programm has to decide here

    let getIntArray = function
        | Sizes arr -> arr
        | Colors _  -> failwith "Given value doesn't contain an int array`
    

    getIntArray foo will work properly but getIntArray (Colors [||]) will fail, but from type-level both are valid.

    Note that if you're completely sure that the operation will succeed, you can use pattern-matching directly:

    let getIntArray (Sizes arr) = arr