<div class="gmail_quote">On Fri, Jun 25, 2010 at 16:36, Andrei Alexandrescu <span dir="ltr"><<a href="mailto:SeeWebsiteForEmail@erdani.org">SeeWebsiteForEmail@erdani.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
<div><div></div><div class="h5">On 06/25/2010 08:39 AM, Graham Fawcett wrote:<br>
<blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">Thank you.<br>
<br>
<a href="http://d.puremagic.com/issues/show_bug.cgi?id=4391" target="_blank">http://d.puremagic.com/issues/show_bug.cgi?id=4391</a><br>
</blockquote>
<br></div></div>
Great. I'm hoping for a patch that fixes the problem, but it's good to have the report we don't forget this.<font color="#888888"></font></blockquote><div><br>I'm using this, without problem up to now, it works for n-args functions (even 0 or 1) and accepts template functions too, but see the doc for the limitation in this case.<br>
<br><br>/**<br>Takes a D function, and curries it (in traditional, mathematical sense): given<br>a n-args function, it creates n 1-arg functions nested inside one another. When<br>all original arguments are reached, it returns the result.<br>
<br>Example:<br>----<br>int add(int i, int j) { return i+j;}<br>alias curry!add cadd; // cadd waits for an int, will return an int delegate(int)<br>auto add3 = cadd(3); // add3 is a function that take an int and return this int + 3.<br>
<br>auto m = map!add3([0,1,2,3]);<br>assert(equal(m, [3,4,5,6]));<br><br>bool equals(int i, int j) { return i==j;}<br>alias curry!equals cequals;<br>auto equals4 = cequals(4); // equals4 is a function taking an int and return true iff this int is 4.<br>
auto f = filter!equals4([2,3,4,5,4,3,2,2,3,4]);<br>assert(equal(f, [4,4,4]));<br>----<br><br>What's fun is that it'll work for template functions too.<br><br>Example:<br>----<br>string conj(A, B)(A a, B b)<br>{<br>
return to!string(a)~to!string(b);<br>}<br><br>alias curry!conj cconj;<br>auto c1 = cconj(1); // c1 is a template function waiting for any type.<br>assert(c1('a') == "1a");<br>----<br>BUG:<br>for now, it does not verify the compatibility of types while you give it the arguments. It's only<br>
at the end that it sees whether or not it can call the function with these arguments.<br>Example:<br>----<br>// given a function like this, with dependencies between the arguments' types:<br>A foo(A,B,C)(A a, Tuple!(B,A) b, Tuple!(C,B,A) c) { return a+b.field[1]+c.field[2];}<br>
// if you curries it and gives it an int as first argument, the returned template function should really be:<br>int foo2(B,C)(Tuple!(B,int) b) { return anotherFunction;}<br>// because we now know A to be an int...<br>----<br>
*/<br>template curry(alias fun)<br>{<br> static if (isFunction!fun)<br> enum curry = mixin(curryImpl!(fun, "", ParameterTypeTuple!fun));<br> else<br> enum curry = curriedFunction!(fun)();<br>
}<br><br>template curryImpl(alias fun, string xs, T...)<br>{<br> static if (T.length == 0)<br> enum curryImpl = "&fun";<br> else static if (T.length == 1)<br> enum curryImpl = "(" ~ T[0].stringof ~ " x1) { return fun(" ~ xs ~ "x1);}";<br>
else<br> enum curryImpl = "(" ~ T[0].stringof ~ " x" ~ to!string(T.length) ~ ") { return "<br> ~ curryImpl!(fun,xs ~ "x" ~ to!string(T.length) ~ ", ", T[1..$]) ~ ";}";<br>
}<br><br>struct CurriedFunction(alias fun, T...) /+if (T.length)+/<br>{<br> T _t;<br> static if (T.length)<br> void initialize(T t) { _t = t;}<br><br> template OpCallType(U...)<br> {<br> static if (is (typeof(fun(Init!T, Init!U))))<br>
alias typeof(fun(Init!T, Init!U)) OpCallType;<br> else<br> alias CurriedFunction!(fun, T, U) OpCallType;<br> }<br><br> OpCallType!U opCall(U...)(U u)<br> {<br> static if(is(typeof(fun(_t, u))))<br>
return fun(_t,u);<br> else<br> {<br> CurriedFunction!(fun, T, U) cf;<br> static if (U.length) cf.initialize(_t, u);<br> return cf;<br> }<br> }<br>}<br><br>
CurriedFunction!(fun, TypeTuple!()) curriedFunction(alias fun)()<br>{<br> CurriedFunction!(fun, TypeTuple!()) cf;<br> return cf;<br>}<br><br>unittest<br>{<br> int add(int i, int j) { return i+j;}<br> alias curry!add cadd; // cadd waits for an int, will return an int delegate(int)<br>
auto add3 = cadd(3); // add3 is a function that take an int and return this int + 3.<br><br> auto m = map!add3([0,1,2,3]);<br> assert(equal(m, [3,4,5,6]));<br><br> bool equals(int i, int j) { return i==j;}<br>
alias curry!equals cequals;<br> auto equals4 = cequals(4); // equals4 is a function taking an int and return true iff this int is 4.<br> auto f = filter!equals4([2,3,4,5,4,3,2,2,3,4]);<br> assert(equal(f, [4,4,4]));<br>
}<br> <br><br>So, the template function part is still a bit rough. I've plan to keep track of types dependencies, but ... well, Real Life (tm) is in the way.<br><br>I posted it as a comment in the bug report, in case it can help someone write something.<br>
<br>Philippe<br><br></div></div>