How to pattern-match when something is NOT of a particular type

245 views Asked by At

We're all used to pattern-matching for cases when something is a particular type, e.g.,

match x with
| Y(x) :: tail -> ... // assumes List.head(x) is of type Y(x)

But how can can I match the case when something is not of a particular type? E.g.,

match x with
| Not Y(_) :: tail -> ... // List.head(x) is definitely not a Y

Thanks!

2

There are 2 answers

0
gradbot On BEST ANSWER

While there is no direct support for Not you can use a partial active pattern.

type Color = | Red | Green | Blue

let (|NotRed|_|) = function
    | Red -> None
    | color -> Some color

let rec print = function
    | (NotRed head) :: tail -> 
        printfn "%A is Not Red" head
        print tail
    | _ :: tail -> print tail
    | _ -> ()

print [Red; Green; Blue]

output

Green is Not Red
Blue is Not Red
1
Tomas Petricek On

I think the usual way to deal with this is to first write a clause that explicitly excludes the cases you don't want. Then you can use _ to handle all remaining cases (You need to write some code for the case you want to exclude, but that needs to be written anyway to make the pattern matching complete):

match x with
| Y _ :: tail -> ()
| _ :: tail -> // List.head(x) is definitely not a Y

This definitely feels like a workaround, but I'm afraid that's the best you can do. If you wanted to exclude multiple cases, you can write something like:

match x with
| (Y _ | (Z (1 | 2 | 3 | 4)) :: tail -> ()
| _ :: tail -> // Excludes all "Y x" and "Z n when n \in 1,2,3,4"

Anyway, this is a very interesting question - I'm wondering if the language of patterns could be extended with some special pattern for expressing negation... Interestingly, this is not something that could be directly written using active patterns.