www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 4391] New: std.functional.curry is not a real curry

reply d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=4391

           Summary: std.functional.curry is not a real curry
           Product: D
           Version: D2
          Platform: Other
        OS/Version: All
            Status: NEW
          Severity: normal
          Priority: P2
         Component: Phobos
        AssignedTo: nobody puremagic.com
        ReportedBy: graham.fawcett gmail.com


--- Comment #0 from Graham Fawcett <graham.fawcett gmail.com> 2010-06-25
06:37:50 PDT ---
The "curry" template in std.functional is not actually a curry, but a partial
application. 

A curry function should take a single argument, a binary function:

  (A a, B b) { return ... }

and return a nested unary function:

  (A a) { return (B b) { return ... }; };

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Jun 25 2010
next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=4391


Philippe Sigaud <philippe.sigaud gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |philippe.sigaud gmail.com


--- Comment #1 from Philippe Sigaud <philippe.sigaud gmail.com> 2010-06-25
21:13:39 CEST ---
(In reply to comment #0)

Here is a possible patch:

/**
Takes a D function, and curries it (in traditional, mathematical sense): given
a n-args function, it creates n 1-arg functions nested inside one another. When
all original arguments are reached, it returns the result.

Example:
----
int add(int i, int j) { return i+j;}
alias curry!add cadd; // cadd waits for an int, will return an int
delegate(int)
auto add3 = cadd(3); // add3 is a function that take an int and return this int
+ 3.

auto m = map!add3([0,1,2,3]);
assert(equal(m, [3,4,5,6]));

bool equals(int i, int j) { return i==j;}
alias curry!equals cequals;
auto equals4 = cequals(4); // equals4 is a function taking an int and return
true iff this int is 4.
auto f = filter!equals4([2,3,4,5,4,3,2,2,3,4]);
assert(equal(f, [4,4,4]));
----

What's fun is that it'll work for template functions too.

Example:
----
string conj(A, B)(A a, B b)
{
    return to!string(a)~to!string(b);
}

alias curry!conj cconj;
auto c1 = cconj(1); // c1 is a template function waiting for any type.
assert(c1('a') == "1a");
----
BUG:
for now, it does not verify the compatibility of types while you give it the
arguments. It's only
at the end that it sees whether or not it can call the function with these
arguments.
Example:
----
// given a function like this, with dependencies between the arguments' types:
A foo(A,B,C)(A a, Tuple!(B,A) b, Tuple!(C,B,A) c) { return
a+b.field[1]+c.field[2];}
// if you curries it and gives it an int as first argument, the returned
template function should really be:
int foo2(B,C)(Tuple!(B,int) b) { return anotherFunction;}
// because we now know A to be an int...
----
*/
template curry(alias fun)
{
    static if (isFunction!fun)
        enum curry =  mixin(curryImpl!(fun, "", ParameterTypeTuple!fun));
    else
        enum curry = curriedFunction!(fun)();
}

template curryImpl(alias fun, string xs, T...)
{
    static if (T.length == 0)
        enum curryImpl = "&fun";
    else static if (T.length == 1)
        enum curryImpl = "(" ~ T[0].stringof  ~ " x1) { return fun(" ~ xs ~
"x1);}";
    else
        enum curryImpl = "(" ~ T[0].stringof  ~ " x" ~ to!string(T.length) ~ ")
{ return "
                            ~ curryImpl!(fun,xs ~ "x" ~ to!string(T.length) ~
", ", T[1..$]) ~ ";}";
}

struct CurriedFunction(alias fun, T...) /+if (T.length)+/
{
    T _t;
    static if (T.length)
        void initialize(T t) { _t = t;}

    template OpCallType(U...)
    {
        static if (is (typeof(fun(Init!T, Init!U))))
            alias typeof(fun(Init!T, Init!U)) OpCallType;
        else
            alias CurriedFunction!(fun, T, U) OpCallType;
    }

    OpCallType!U opCall(U...)(U u)
    {
        static if(is(typeof(fun(_t, u))))
            return fun(_t,u);
        else
        {
            CurriedFunction!(fun, T, U) cf;
            static if (U.length) cf.initialize(_t, u);
            return cf;
        }
    }
}

CurriedFunction!(fun, TypeTuple!()) curriedFunction(alias fun)()
{
    CurriedFunction!(fun, TypeTuple!()) cf;
    return cf;
}

unittest
{
    int add(int i, int j) { return i+j;}
    alias curry!add cadd; // cadd waits for an int, will return an int
delegate(int)
    auto add3 = cadd(3); // add3 is a function that take an int and return this
int + 3.

    auto m = map!add3([0,1,2,3]);
    assert(equal(m, [3,4,5,6]));

    bool equals(int i, int j) { return i==j;}
    alias curry!equals cequals;
    auto equals4 = cequals(4); // equals4 is a function taking an int and
return true iff this int is 4.
    auto f = filter!equals4([2,3,4,5,4,3,2,2,3,4]);
    assert(equal(f, [4,4,4]));
}


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.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Jun 25 2010
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=4391


Andrei Alexandrescu <andrei metalanguage.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |ASSIGNED
                 CC|                            |andrei metalanguage.com
         AssignedTo|nobody puremagic.com        |andrei metalanguage.com


-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Jan 09 2011
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=4391


timon.gehr gmx.ch changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |timon.gehr gmx.ch


--- Comment #2 from timon.gehr gmx.ch 2011-06-09 11:16:23 PDT ---
I suggest to also keep the current implementation of "curry", but to rename it
to "partial".

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Jun 09 2011
prev sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=4391


klickverbot <code klickverbot.at> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |code klickverbot.at


--- Comment #3 from klickverbot <code klickverbot.at> 2011-09-03 17:53:09 PDT
---
 Timon: Agreed, having a »curry« that really performs partial application is
quite confusing (and gets us into trouble if we want to add a real curry), this
has been on my todo list for quite some time now.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Sep 03 2011