Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I determine if a list of discriminated union types are of the same case?

Tags:

f#

Suppose I have a DU like so:

type DU = Number of int | Word of string

And suppose I create a list of them:

[Number(1); Word("abc"); Number(2)]

How can I write a function that would return true for a list of DUs where all the elements are the same case. For the above list it should return false.

like image 709
DNg Avatar asked Sep 10 '16 21:09

DNg


People also ask

How is a discriminated union defined?

A discriminated union is a union data structure that holds various objects, with one of the objects identified directly by a discriminant. The discriminant is the first item to be serialized or deserialized. A discriminated union includes both a discriminant and a component.

Why are unions discriminated?

Discriminated unions are useful for heterogeneous data; data that can have special cases, including valid and error cases; data that varies in type from one instance to another; and as an alternative for small object hierarchies.

What is discriminated unions in TypeScript?

The concept of discriminated unions is how TypeScript differentiates between those objects and does so in a way that scales extremely well, even with larger sets of objects. As such, we had to create a new ANIMAL_TYPE property on both types that holds a single literal value we can use to check against.

What is union type in TS?

Union types are used when a value can be more than a single type. Such as when a property would be string or number .


1 Answers

The general approach I'd use here would be to map the union values into tags identifying the cases, and then check if the resulting set of tags has at most one element.

let allTheSameCase (tagger: 'a -> int) (coll: #seq<'a>) = 
    let cases = 
        coll
        |> Seq.map tagger
        |> Set.ofSeq
    Set.count cases <= 1 

For the tagger function, you can assign the tags by hand:

 allTheSameCase (function Number _ -> 0 | Word _ -> 1) lst

or use reflection (note that you might need to set binding flags as necessary):

 open Microsoft.FSharp.Reflection

 let reflectionTagger (case: obj) = 
    let typ = case.GetType()
    if FSharpType.IsUnion(typ)
        then 
            let info, _ = FSharpValue.GetUnionFields(case, typ) 
            info.Tag
        else -1 // or fail, depending what makes sense in the context.
like image 125
scrwtp Avatar answered Nov 15 '22 12:11

scrwtp