3
votes

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?

1

1 Answers

5
votes

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?