Re: Why doesn't curry work with multiple arguments?

2011-04-06 Thread Andrej Mitrovic
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


Re: Why doesn't curry work with multiple arguments?

2011-04-06 Thread Andrej Mitrovic
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.


Re: Why doesn't curry work with multiple arguments?

2011-04-06 Thread Andrej Mitrovic
Crap, that is a horrible implementation, I didn't take into account
not binding all arguments. Be right back..


Re: Why doesn't curry work with multiple arguments?

2011-04-06 Thread Andrej Mitrovic
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);
}
}
}
}


Re: Why doesn't curry work with multiple arguments?

2011-04-06 Thread Andrej Mitrovic
It's still wrong, the tuple is backwards. Haha, that's what I get for
not unittesting.


Re: Why doesn't curry work with multiple arguments?

2011-04-06 Thread bearophile
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


Re: Why doesn't curry work with multiple arguments?

2011-04-06 Thread Andrej Mitrovic
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();
}


Re: Why doesn't curry work with multiple arguments?

2011-04-06 Thread Andrej Mitrovic
On 4/6/11, bearophile bearophileh...@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..


Re: Why doesn't curry work with multiple arguments?

2011-04-06 Thread bearophile
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


Re: Why doesn't curry work with multiple arguments?

2011-04-06 Thread Andrej Mitrovic
Well this still hasn't solved my problem. Because I shouldn't bind
from left to right, but arbitrarily.

So ideally I would want this:

void foo(string str, int x, int y, string str2) { }

alias bind!(foo, null, 1, 2, null) twoStrings;
twoStrings(abc, def);   -   foo(abc, 1, 2, def);

I'm pretty sure I could do this with D's templates.