Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

F# Avoid active pattern overwriting

I have noticed I cannot create two active patterns with the same options, but I can have two with similar ones without any warning:

let (|A|B|C|) c =
   if (c = 'a') then A
   else if (c = 'b') then B
   else C

let (|A|B|D|) c =
   if (c = '1') then A
   else if (c = '2') then B
   else D

So when matching this way:

let check myvar =
  match myvar with 
    | A -> printf "match A\n"
    | n -> printf "match other %A\n" n

This happens:

check 'x' // match other 'x'  
check 'a' // match other 'a'     !!
check '1' // match A

I am a bit concerned of overwriting existing active pattern options inadvertently, for example in situations where the same word can appear in different patterns because different semantic contexts, like (|Direct|Indirect|) (route) and (|Alternating|Direct|) (current).

How can I avoid this situations?

like image 200
vtortola Avatar asked Apr 20 '26 01:04

vtortola


1 Answers

I agree that shadowing of active patterns can be tricky - though it is the same problem that you get with discriminated union cases and record labels in F#. In case of types, you can always include the type name to resolve the ambiguity.

In case of active patterns, you can put them in modules - for example Pat1 and Pat2:

module Pat1 =
 let (|A|B|C|) c =
   if (c = 'a') then A
   else if (c = 'b') then B
   else C

module Pat2 =
 let (|A|B|D|) c =
   if (c = '1') then A
   else if (c = '2') then B
   else D

So, in your code, you can then use fully qualified name like Pat1.A or Pat2.A:

let check myvar =
  match myvar with 
  | Pat1.A -> printf "match A\n"
  | n -> printf "match other %A\n" n
like image 121
Tomas Petricek Avatar answered Apr 23 '26 16:04

Tomas Petricek