digitalmars.D - Pattern matching example
- bearophile (7/7) Apr 03 2010 I'm not currently asking to implement pattern matching in D3 (as present...
- Lutger (39/47) Apr 04 2010 It was a subthread under the 'is D a cult' thread, this was the basic
- Lutger (8/21) Apr 04 2010 Forgot to add: it is of course possible to adjust matcher to accept some...
- Philippe Sigaud (62/79) Apr 04 2010 I went the other way round and wrote something more compile-time oriente...
I'm not currently asking to implement pattern matching in D3 (as present for example in Scala), but it's positive to think how to solve similar problems in D2, because even if pattern matching is not available in D2, the problems it is asked to solve solve can be real. Walter or Andrei has recently shown here a possible implementation idea, but I don't remember where the post is and what the implementation was. And it wasn't a small compilable program. Recently the RosettaCode site has added a small but real problem to solve with pattern matching. It can be a quite good example to see how D2 can be used solve this problem: http://rosettacode.org/wiki/Pattern_matching RosettaCode site is nice, because among its various purposes, it can be advertisement too for the D language. That's why I (and Downs and probably others here) have written many solutions in D1/D2 for that site. So I even suggest to put a link to to RosettaCode somewhere in the D section of the digitalmars site, to turn it into a semi-official thing. Bye, bearophile
Apr 03 2010
bearophile wrote:I'm not currently asking to implement pattern matching in D3 (as present for example in Scala), but it's positive to think how to solve similar problems in D2, because even if pattern matching is not available in D2, the problems it is asked to solve solve can be real. Walter or Andrei has recently shown here a possible implementation idea, but I don't remember where the post is and what the implementation was. And it wasn't a small compilable program.It was a subthread under the 'is D a cult' thread, this was the basic example: foo( v, (int i) { writeln("I saw an int ", i); }, (string s) { writeln("I saw a string ", s); ), (Variant any) { writeln("I saw the default case ", any); } ); The criticism was that this only does matching on type. Matching on strings and integers should be done with case statements and other values with if- else. I don't have the time to implement this, but after some hacking I found that something like the following could be made to work, exploiting AA initializers. I'm not sure how efficient it would be though: void matcher(T, C...)(T value, C Cases) { foreach( Case ; Cases) { static if ( is(typeof(Case.keys) == T[])) { if (value in Case) { auto fun = Case[value]; fun(value); } } } } void main(string[] args) { int i = 12; matcher(i, [ "aha": (string v) { writeln("I saw a string ", v); } ], [ 12 : (int i) { writeln("I saw an int ", i); } ] ); string v = "aha"; matcher(v, [ "aha" : (string v) { writeln("I saw a string ", v); } ], [ 12 : (int i) { writeln("I saw an int ", i); } ] ); }
Apr 04 2010
Lutger wrote: ...void main(string[] args) { int i = 12; matcher(i, [ "aha": (string v) { writeln("I saw a string ", v); } ], [ 12 : (int i) { writeln("I saw an int ", i); } ] ); string v = "aha"; matcher(v, [ "aha" : (string v) { writeln("I saw a string ", v); } ], [ 12 : (int i) { writeln("I saw an int ", i); } ] ); }Forgot to add: it is of course possible to adjust matcher to accept something like this: matcher(v, [ "aha" : (string v) { writeln("I saw a string ", v); }, (string v) { writeln("default case for string ", v); }, [ 12 : (int i) { writeln("I saw an int ", i); } ] );
Apr 04 2010
On Sun, Apr 4, 2010 at 17:18, Lutger <lutger.blijdestijn gmail.com> wrote:bearophile wrote:I went the other way round and wrote something more compile-time oriented: usage: match!(fun1, fun2, fun3)(someValues...); // as many values as you wish where the funX can be template functions (or anything template-y _and_ callable), to harness the pattern matching inherent in templates, variadic templates, and so on. For example, given: string any(T...)(T t) { return "any: " ~ typeof(t).stringof;} T one(T)(T t) { return t;} T[] twoEqual(T)(T t1, T t2) { return [t1,t2];} Tuple!(T,U) twoDiff(T,U)(T t, U u) { return tuple(t,u);} string three(T)(T t1, T t2, T t3) { return T.stringof ~ " thrice";} you can do: alias match!(one, twoEqual, twoDiff, three, any) matcher; auto m = matcher(1); // 1 auto m = matcher(1,2); // [1,2] auto m = matcher(1,'a'); // Tuple!(int,char)(1,'a') auto m = matcher(1,2,3,4); // string "any: (int,int,int,int)" You can also use standard functions, of course, and mix templates and functions. I used this to create trees of tuples (tuples of values and tuples) and pattern-match on them. It's far from being as beautiful as Haskell code, but it's enough for my needs. One interest compared to function overload is that you can have different return types depending on the function you give it as params. I have another version that deconstruct the values: if you send it a struct containing two ints and one of your function has two ints as params, it will match. But it's buggy as hell and I sould have a look at it before posting it. For match, here is the code: template match(alias fun, Rest...) { auto match(M...)(M m) { // curried template... return Matcher!(fun, M.length, M, Rest)(m)(); } } struct Matcher(alias fun, size_t n, Rest...) { TypeTuple!(Rest[0..n]) _m; this(TypeTuple!(Rest[0..n]) m) { _m = m;} auto opCall() { static if (is(typeof(fun(_m)))) return fun(_m); else static if (n == 1 && is(typeof(fun(_m[0])))) // I'm not sure this is necessary return fun(_m[0]); else static if (Rest.length > n) { return Matcher!(Rest[n], n, Rest[0..n], Rest[n+1..$])(_m)(); } else { // no match found, we are at the end of Rest string s; foreach(i, Type; TypeTuple!(Rest[0..n])) s ~= to!string(_m[i]); throw new NoMatchException("No match for " ~ s ~ " of type " ~ typeof(_m).stringof); } } } Half the complexity and ugliness comes from my wanting to have a variadic function in the end: I did_not_ want have to wrap my arguments in a tuple, as it's done for std.concurrency, IIRC. Also, I use functions like (...) { some code } or (T...)(T t) { } to get a function that matches everything, not a (Variant v) { } PhilippeI'm not currently asking to implement pattern matching in D3 (as present for example in Scala), but it's positive to think how to solve similar problems in D2, because even if pattern matching is not available in D2, the problems it is asked to solve solve can be real. Walter or Andrei has recently shown here a possible implementation idea, but I don't remember where the post is and what the implementation was.Andit wasn't a small compilable program.It was a subthread under the 'is D a cult' thread, this was the basic example: foo( v, (int i) { writeln("I saw an int ", i); }, (string s) { writeln("I saw a string ", s); ), (Variant any) { writeln("I saw the default case ", any); } );
Apr 04 2010