<div class="gmail_quote">On Fri, Jun 25, 2010 at 16:36, Andrei Alexandrescu <span dir="ltr">&lt;<a href="mailto:SeeWebsiteForEmail@erdani.org">SeeWebsiteForEmail@erdani.org</a>&gt;</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&#39;m hoping for a patch that fixes the problem, but it&#39;s good to have the report we don&#39;t forget this.<font color="#888888"></font></blockquote><div><br>I&#39;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&#39;s fun is that it&#39;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(&#39;a&#39;) == &quot;1a&quot;);<br>----<br>BUG:<br>for now, it does not verify the compatibility of types while you give it the arguments. It&#39;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&#39; 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, &quot;&quot;, 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 = &quot;&amp;fun&quot;;<br>    else static if (T.length == 1)<br>        enum curryImpl = &quot;(&quot; ~ T[0].stringof  ~ &quot; x1) { return fun(&quot; ~ xs ~ &quot;x1);}&quot;;<br>
    else<br>        enum curryImpl = &quot;(&quot; ~ T[0].stringof  ~ &quot; x&quot; ~ to!string(T.length) ~ &quot;) { return &quot;<br>                            ~ curryImpl!(fun,xs ~ &quot;x&quot; ~ to!string(T.length) ~ &quot;, &quot;, T[1..$]) ~ &quot;;}&quot;;<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&#39;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>