1 module nxt.functional_ex; 2 3 import std.traits; 4 import std.conv; 5 import std.variant; 6 7 /** Pattern Matching. 8 See_Also: http://forum.dlang.org/post/ijjthwfezebkszkzrcgt@forum.dlang.org 9 */ 10 auto ref match(Handlers...)(Variant v) 11 { 12 foreach (Handler; Handlers) 13 { 14 alias P = Parameters!Handler; 15 static if (P.length == 1) 16 { 17 static if (is(P[0] == CMatch!(_), _)) 18 { 19 if (P[0].match(v)) 20 return Handler(P[0].init); 21 } 22 else 23 { 24 if (auto p = v.peek!(P[0])) 25 return Handler(*p); 26 } 27 } 28 else 29 { 30 return Handler(); 31 } 32 } 33 assert(0, "No matching pattern"); 34 } 35 36 private struct CMatch(T...) 37 if (T.length == 1) 38 { 39 alias U = typeof(T[0]); 40 static bool match(Variant v) 41 { 42 if (auto p = v.peek!U) 43 return *p == T[0]; 44 return false; 45 } 46 } 47 48 /// 49 unittest { 50 Variant v = 5; 51 string s = v.match!((CMatch!7) => "Lucky number seven", 52 (int n) => "Not a lucky number: " ~ n.to!string, 53 () => "No value found!"); 54 // import std.stdio; 55 // writeln(s); 56 } 57 58 /** Turn the function what into a curried function. 59 * 60 * See_Also: https://stackoverflow.com/questions/58147381/template-for-currying-functions-in-d 61 */ 62 template autocurry(alias Fun) 63 if (isCallable!Fun) 64 { 65 alias P = Parameters!Fun; 66 static if (P.length) 67 { 68 auto autocurry(P[0] arg) 69 { 70 alias Remainder = P[1 .. $]; // remainder 71 auto dg = delegate(Remainder args) 72 { 73 return Fun(arg, args); 74 }; 75 static if (Remainder.length > 1) 76 return &autocurry!dg; 77 else 78 return dg; 79 } 80 } 81 else 82 { 83 alias autocurry = Fun; 84 } 85 } 86 87 /// 88 pure @safe unittest { 89 static float foo(int a, string b, float c) pure nothrow @safe @nogc 90 => a + b.length + c; 91 alias foo_ = autocurry!foo; // overloads the auto-curried foo with the original foo 92 assert(foo_(52)("alpha")(1) == 58); 93 }