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 (isInstanceOf!(CMatch, P[0])) 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 { 51 Variant v = 5; 52 string s = v.match!((CMatch!7) => "Lucky number seven", 53 (int n) => "Not a lucky number: " ~ n.to!string, 54 () => "No value found!"); 55 // import std.stdio; 56 // writeln(s); 57 } 58 59 /** Turn the function what into a curried function. 60 * 61 * See_Also: https://stackoverflow.com/questions/58147381/template-for-currying-functions-in-d 62 */ 63 template autocurry(alias Fun) 64 if (isCallable!Fun) 65 { 66 alias P = Parameters!Fun; 67 static if (P.length) 68 { 69 auto autocurry(P[0] arg) 70 { 71 alias Remainder = P[1 .. $]; // remainder 72 auto dg = delegate(Remainder args) 73 { 74 return Fun(arg, args); 75 }; 76 static if (Remainder.length > 1) 77 return &autocurry!dg; 78 else 79 return dg; 80 } 81 } 82 else 83 { 84 alias autocurry = Fun; 85 } 86 } 87 88 /// 89 @safe pure unittest 90 { 91 static float foo(int a, string b, float c) @safe pure nothrow @nogc 92 { 93 return a + b.length + c; 94 } 95 alias foo_ = autocurry!foo; // overloads the auto-curried foo with the original foo 96 assert(foo_(52)("alpha")(1) == 58); 97 }