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.


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
On 4/6/11, bearophile  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 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 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
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 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
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
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
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


Why doesn't curry work with multiple arguments?

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