Question

In the following real world example I do a match:

type Style = Nice | Cool | Ugly
type Color = Blue | Yellow | Orange | Grey | Cyan
type ClothingProperties = Style * Color

type Clothes =
| Jeans of ClothingProperties
| Pullover of ClothingProperties
| Shirt of ClothingProperties

type Person =
| Person of string * Clothes

let team = [Person("Jan", Jeans (Cool, Blue)); Person("Pete", Shirt (Nice, Cyan)); Person("Harry", Pullover (Ugly, Grey))]

let matchPerson person=
    match person with
    | Person(name,  Jeans(Ugly,_) ) -> printfn "%s wears ugly stuff." name
    | Person(name,  Pullover(Ugly,_) ) -> printfn "%s wears ugly stuff." name
    | Person(name,  Shirt(Ugly,_) ) -> printfn "%s wears ugly stuff." name
    | _ -> ()

List.iter(fun x->matchPerson x) team

Is there a way to create a more efficient match, so I don't need to check each clothing case? Something like this:

let matchPerson person=
    match person with
    | Person(name,  _ (Ugly,_) ) -> printfn "%s wears ugly stuff." name
    | _ -> ()

Of course, this is not correct syntax. But how can I achieve such an effect?

Was it helpful?

Solution

That's not straightforward, you can use reflection, but the problem is that your discriminated union needs some redesign, because if you know there will always be a ClothingProperties then you can change it to this:

type Style = Nice | Cool | Ugly
type Color = Blue | Yellow | Orange | Grey | Cyan
type ClothingProperties = Style * Color // or just use a tuple

type Clothe =
| Jeans 
| Pullover
| Shirt

type Clothes = Clothe *ClothingProperties
type Person =
| Person of string * Clothes

let matchPerson person=
    match person with
    | Person(name,  (_,(Ugly,_)) ) -> printfn "%s wears ugly stuff." name
    | _ -> ()

A related issue is described here Is it possible to pass discriminated union tags as arguments?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top