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 }