Pattern matching as a library

Simen Kjaeraas via Digitalmars-d digitalmars-d at puremagic.com
Sat Mar 12 05:12:56 PST 2016


As I once again bemoaned D's lack of pattern matching yesterday, 
I was inspired to create this[0] implementation, that plays to 
D's strengths, allows for user-defined matching, and has a fairly 
usable syntax. The core usage looks like this:

unittest {
   auto a = tuple(1, "foo");
   auto b = match(a) (
     _!(int, "foo") = (int i) => 1,
     _!(_, _)       = ()      => 0
   );
   assert(b == 1);
}

With the user-defined matching implemented as follows:

struct Tuple(T...) {
    // Implementation

   // Magic happens here
   bool opMatch(Pattern, Args...)(Pattern p, ref Args args) {
     foreach (i, e; p.pattern) {
       static if (isTypeTuple!e) {
         enum n = countTypes!(p.pattern[0..i]);
         args[n] = fields[i];
       } else static if (!ignore!e) {
         if (fields[i] != e) {
           return false;
         }
       }
     }
   }
}

Or for Algebraic:

struct Algebraic(T...) {
   union {
     T fields;
   }
   size_t which;

   bool opMatch(Pattern, Type)(Pattern p, ref Type args) if 
(staticIndexOf!(Type, T) > -1) {
     enum index = staticIndexOf!(Type, T);
     if (index == which) {
       args = fields[index];
       return true;
     }
     return false;
   }
}

The main problem I see is the temporary allocation of function 
arguments on line 124 and their assignment in opMatch, but I 
currently don't have a better solution.

Also, while I very much dislike using _ for an identifier, I feel 
it may be the best alternative here - it conveys the meaning of 
'don't care' for the pattern, and doesn't stand out like a sore 
thumb before the exclamation mark. Other suggestions are welcome.

The code is available here, and I encourage everyone to play with 
it and critique:

[0]: 
https://github.com/Biotronic/Collectanea/blob/master/biotronic/pattern.d


More information about the Digitalmars-d mailing list