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 }