Skip to content

Instantly share code, notes, and snippets.

@alphaKAI
Last active September 4, 2017 08:50
Show Gist options
  • Save alphaKAI/122189b2515f0d72aa23950d93a8ea44 to your computer and use it in GitHub Desktop.
Save alphaKAI/122189b2515f0d72aa23950d93a8ea44 to your computer and use it in GitHub Desktop.
toy pattern matching in D
import std.functional,
std.typecons,
std.traits,
std.meta;
class PatternIsNull {}
class PatternWithValue(P = PatternIsNull, F: R delegate(), R: R) {
P pattern;
F func;
this (F func) {
this.func = func;
}
this (P pattern, F func) {
this.pattern = pattern;
this.func = func;
}
bool match(PX)(PX that_pattern) {
static if (is(P == PX)) {
return that_pattern == this.pattern;
} else static if (isCallable!P && is(ReturnType!P == bool) && is(Parameters!P[0] == PX)) {
return this.pattern(that_pattern);
} else {
return false;
}
}
}
auto _(PT, FT)(PT p, FT f) {
static if (isSomeFunction!FT) {
static if (is(FT == R function(), R: R)) {
return new PatternWithValue!(PT, R delegate())(p, f.toDelegate);
} else {
return new PatternWithValue!(PT, FT)(p, f);
}
} else {
return new PatternWithValue!(PT, FT delegate())(p, delegate FT () { return f; });
}
}
auto _(FT)(FT f) {
static if (isSomeFunction!FT) {
static if (is(FT == R function(), R: R)) {
return new PatternWithValue!(PatternIsNull, R delegate())(f.toDelegate);
} else {
return new PatternWithValue!()(f);
}
} else {
return new PatternWithValue!(PatternIsNull, FT delegate())(delegate FT () { return f; });
}
}
void checkMP_value(MP...)(MP mp) {
static assert (mp.length);
enum bool value_mode = is(typeof(mp[0]) == PatternWithValue!(T, F), T: T, F: F);
foreach (e; mp) {
static if (value_mode) {
static assert (is(typeof(e) == PatternWithValue!(T, F), T: T, F: F));
} else {
static assert (is(typeof(e) == PatternWithValue!(T, F), T: T, F: F)
|| is(typeof(e) == PatternWithType!(T, F), T: T, F: F));
}
}
}
auto match(X, MP...)(X x, MP mp) {
checkMP_value(mp);
enum validate = (is(MP[0] == PatternWithValue!(T, F), T: T, F: F)
|| is(MP[0] == PatternWithType!(T, F), T: T, F: F));
static assert (validate);
PatternWithValue!(PatternIsNull, F) otherwise;
bool exist_otherwise;
foreach (e; mp) {
static if (is(typeof(e) == PatternWithValue!(PatternIsNull, F))) {
otherwise = e;
exist_otherwise = true;
continue;
} else {
if (e.match(x)) {
return e.func();
}
}
}
if (!exist_otherwise) {
return otherwise.func();
} else {
throw new Error("No pattern matched");
}
}
class PatternWithType(P = PatternIsNull, F: R delegate(), R: R) {
F func;
this (F func) {
this.func = func;
}
bool match(X)() {
static if (is(P == X)) {
return true;
} else {
return false;
}
}
bool match(X)(X x) {
if (!isBuiltinType!P && !isPointer!X) {
return cast(P)x !is null;
} else {
return false;
}
}
}
auto _(PT, FT)(FT f) {
static if (isSomeFunction!FT) {
static if (is(FT == R function(), R: R)) {
return new PatternWithType!(PT, R delegate())(f.toDelegate);
} else {
return new PatternWithType!(PT, FT)(f);
}
} else {
return new PatternWithType!(PT, FT delegate())(delegate FT () { return f; });
}
}
void checkMP_type(MP...)(MP mp) {
static assert (mp.length);
foreach (e; mp) {
static assert (is(typeof(e) == PatternWithType!(T, F), T: T, F: F)
|| is(typeof(e) == PatternWithValue!(PatternIsNull, F), F: F));
}
}
auto match(T, MP...)(MP mp) {
checkMP_type(mp);
enum validate = (is(MP[0] == PatternWithValue!(PatternIsNull, F), F: F)
|| is(MP[0] == PatternWithType!(T, F), T: T, F: F));
static assert (validate);
PatternWithValue!(PatternIsNull, F) otherwise;
bool exist_otherwise;
foreach (e; mp) {
static if (is(typeof(e) == PatternWithValue!(PatternIsNull, F))) {
otherwise = e;
exist_otherwise = true;
continue;
} else {
if (e.match!T()) {
return e.func();
}
}
}
if (!exist_otherwise) {
return otherwise.func();
} else {
throw new Error("No pattern matched");
}
}
import std.stdio;
interface AorB {}
class A : AorB {}
class B : AorB {}
enum E { A,B }
string pz() { return "pattern z"; }
void main() {
string x = "z";
x.match(
"x"._({ writeln("pattern x"); }),
"y"._({ writeln("pattern y"); }),
((string z) => z == "z")._({writeln("pattern z");}),
_({ writeln("otherwise"); }));
string ret = x.match(
"x"._(() => "pattern x"),
"y"._(() => "pattern y"),
((string z) => z == "z")._(pz),
_(() => ("otherwise"))); assert (ret == "pattern " ~ x);
string ret2 = x.match(
"x"._("pattern x"),
"y"._("pattern y"),
((string z) => z == "z")._("pattern z"),
_("otherwise")); assert (ret2 == "pattern " ~ x);
match!(typeof(1))(
_!string({ writeln("pattern string"); }),
_!int({ writeln("pattern int"); }),
_({ writeln("otherwise"); }));
AorB aorb = new A;
aorb.match(
_!A({ writeln("pattern A"); }),
_!B({ writeln("pattern B"); }),
_({ writeln("otherwise"); }));
E eab = E.B;
eab.match(
E.A._({ writeln("pattern A"); }),
E.B._({ writeln("pattern B"); }),
_({ writeln("otherwise"); }));
string ret3 = eab.match(
E.A._( "pattern E.A" ),
E.B._( "pattern E.B" ),
_("otherwise")); assert (ret3 == "pattern E.B");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment