[Issue 5829] New: An improvement or alternative to std.functional.curry

d-bugmail at puremagic.com d-bugmail at puremagic.com
Sun Apr 10 12:09:00 PDT 2011


http://d.puremagic.com/issues/show_bug.cgi?id=5829

           Summary: An improvement or alternative to std.functional.curry
           Product: D
           Version: D2
          Platform: Other
        OS/Version: Windows
            Status: NEW
          Severity: normal
          Priority: P2
         Component: Phobos
        AssignedTo: nobody at puremagic.com
        ReportedBy: andrej.mitrovich at gmail.com


--- Comment #0 from Andrej Mitrovic <andrej.mitrovich at gmail.com> 2011-04-10 12:05:16 PDT ---
Currently, std.functional.curry only accepts binding one argument against a
function. Is there a reason why curry shouldn't be allowed to accept multiple
arguments? Because this is easily possible to do.

Maybe another name for this method would be "partial function application". In
any case, I have a very basic implementation that works with multiple arguments
and even variadic functions. An implementation and a small test case follow:

import std.stdio;
import std.traits;
import std.metastrings;
import std.functional;

template count(T...)
{
    enum count = T.length;
}

template myCurry(alias fun, args...)
{
    static if (__traits(compiles, (ParameterTypeTuple!fun).length))
    {
        static if (args.length > (ParameterTypeTuple!fun).length)
        {
            static assert(0, Format!("Tried to pass too many arguments - %s,
max is %s.",
                                     count!args,
(ParameterTypeTuple!fun).length));
        }
    }

    auto myCurry(T...)(T t)
    {
        return fun(args, t);
    }    
}

void foo(int x, int y, int z)
{
    writefln("%s %s %s", x, y, z);
}

void bar(int[] values...)
{
    foreach (val; values)
    {
        writef("%s ", val);
    }
    writeln();
}

alias myCurry!(foo,    1)     oneFoo;
alias myCurry!(oneFoo, 2)     twoFoo;
alias myCurry!(twoFoo, 3)     threeFoo;
alias myCurry!(foo, 1, 2, 3)  threeFooAgain;
alias myCurry!(foo)           fooNoCurry;

alias myCurry!(bar,    1)   oneBar;
alias myCurry!(oneBar, 2)   twoBar;
alias myCurry!(twoBar, 3)   threeBar;
alias myCurry!(bar)         barNoCurry;

void main()
{
    oneFoo(2, 3);
    twoFoo(3);
    threeFoo();
    threeFooAgain();
    fooNoCurry(1, 2, 3);

    oneBar(2, 3, 4, 5);
    twoBar(3, 4, 5);
    threeBar(4, 5);
    barNoCurry(1, 2, 3, 4, 5);
}

Note that std.functional.curry doesn't work with variadic function parameters,
but the myCurry implementation does.

Three notes:
1. The count template is used because there seems to be a bug if I try to
reference args.length inside a static if body. It's odd since I can reference
args.length inside the static if expression itself, but not its body. Maybe I
should file this as a bug.

2. The first static if is used to allow currying one function against another
already curried function. If I don't check whether a call to
`ParameterTypeTuple` compiles, it will fail with a weird error such as "Tuple
length 1 exceeds length 1". This is possibly another bug.

3. I haven't tested this in thoroughly, so this is a really basic
implementation and it might have bugs. 

In any case I think it would be worthwhile to have a curry-like function that
works with multiple arguments, even if this implementation is too simple. In
that case someone could implement it in a better way.

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


More information about the Digitalmars-d-bugs mailing list