Jump to page: 1 2
Thread overview
Why doesn't curry work with multiple arguments?
Apr 06, 2011
Andrej Mitrovic
Apr 06, 2011
Andrej Mitrovic
Apr 06, 2011
Andrej Mitrovic
Apr 06, 2011
bearophile
Apr 06, 2011
Andrej Mitrovic
Apr 06, 2011
bearophile
Apr 06, 2011
Andrej Mitrovic
Apr 06, 2011
Andrej Mitrovic
Apr 06, 2011
Andrej Mitrovic
Apr 06, 2011
Andrej Mitrovic
Apr 06, 2011
Andrej Mitrovic
April 06, 2011
import std.functional;

void foo(int x, int y, int z)
{
}

alias curry!(foo, 1, 2, 3) bar;

Error: template instance curry!(foo,1,2,3) does not match template declaration curry(alias fun,alias arg)

Shouldn't curry take a variable number of arguments and then check the length of the arguments passed in against `fun`s length of parameters, and do its work from there?

I'm trying to translate a C header file from the following to a D equivalent: #define txmOpenFile(hwndTV, szFile) \

                  SendMessage((hwndTV), TXM_OPENFILE, 0, (LPARAM)(szFile))

Yes, I write a whole new function, but why do that when curry is there. Or so I thought..
April 06, 2011
Andrej Mitrovic Wrote:
> Yes, I write a whole new function, but why do that when curry is there. Or so I thought..

Oops: *Yes, I _can_ write a whole new function
April 06, 2011
Here's a basic implementation:

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

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

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

    static if (is(typeof(fun) == delegate) || is(typeof(fun) == function))
    {
        ReturnType!fun curry()
        {
            return fun(args);
        }
    }
}

void foo(int x, int y)
{
    writeln(x, y);
}

alias curry!(foo, 1, 2) bar;

void main()
{
	bar();
}

It will complain if you try to pass it more arguments than a function can take. I didn't implement curry's original else clause because I have no idea what's going on there (some comments would be useful in Phobos implementations, people!......)

There is some wacky error if I didn't use the count template
workaround. If I try to use args.length twice, like so:
    static if (args.length > (ParameterTypeTuple!fun).length)
    {
        static assert(0, Format!("Tried to pass %s arguments, max is %s.",
                                 args.length, (ParameterTypeTuple!fun).length));
    }

Then I get back: identifier 'length' of 'args.length' is not defined

But it only errors out in the static assert, and yet it can check args.length in the static if. Really weird.
April 06, 2011
Crap, that is a horrible implementation, I didn't take into account not binding all arguments. Be right back..
April 06, 2011
Ok, enjoy this monstrosity:

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

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

    static if (is(typeof(fun) == delegate) || is(typeof(fun) == function))
    {
        static if ((ParameterTypeTuple!fun).length - count!args)
        {
            ReturnType!fun myCurry(ParameterTypeTuple!fun[0 ..
(ParameterTypeTuple!fun).length - count!args] myarg)
            {
                return fun(args, myarg);
            }
        }
        else
        {
            ReturnType!fun myCurry()
            {
                return fun(args);
            }
        }
    }
}
April 06, 2011
It's still wrong, the tuple is backwards. Haha, that's what I get for not unittesting.
April 06, 2011
Andrej Mitrovic:

> Here's a basic implementation:

I have some general comments:
- Currying and partial function application are not exactly the same thing. So I am not sure the "curry" in std.functional is named correctly;
- Partial application is important in a language that wants to support functional idioms a little. This means that if D doesn't currently supports Partial application well, then it's worth improving;
- A good function application must be able to solve this little rosettacode task too:
http://rosettacode.org/wiki/Partial_function_application

Bye,
bearophile
April 06, 2011
Wow, talk about enlightement. I think I've done it now:

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

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

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

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

void foo(string x, int y, int z)
{
    writeln(x, y, z);
}

alias myCurry!(foo, "bar")       oneCurry;
alias myCurry!(foo, "bar", 1)    twoCurry;
alias myCurry!(foo, "bar", 1, 2) threeCurry;

void main()
{
    oneCurry(1, 2);
    twoCurry(2);
    threeCurry();
}
April 06, 2011
On 4/6/11, bearophile <bearophileHUGS@lycos.com> wrote:
> - Currying and partial function application are not exactly the same thing. So I am not sure the "curry" in std.functional is named correctly;

Maybe "bind" should be a better name. I'm not sure..
April 06, 2011
Andrej Mitrovic:

> Maybe "bind" should be a better name. I'm not sure..

In Python there is something similar that's named "partial": http://docs.python.org/library/functools.html#functools.partial

Bye,
bearophile
« First   ‹ Prev
1 2