3

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!

Frank
  • 2,738
  • 19
  • 30
Dmitri Nesteruk
  • 23,067
  • 22
  • 97
  • 166

2 Answers2

4

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.

Tomas Petricek
  • 240,744
  • 19
  • 378
  • 553
  • Thanks! I tried doing it with active patterns but realized it was impossible. The way you describe it is the way I'm currently doing it, but I'm not liking it much :) – Dmitri Nesteruk Feb 22 '11 at 15:41
4

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
gradbot
  • 13,732
  • 5
  • 36
  • 69