digitalmars.D.learn - Why doesn't curry work with multiple arguments?
- Andrej Mitrovic (11/11) Apr 06 2011 import std.functional;
- Andrej Mitrovic (2/3) Apr 06 2011 Oops: *Yes, I _can_ write a whole new function
- Andrej Mitrovic (46/46) Apr 06 2011 Here's a basic implementation:
- bearophile (8/9) Apr 06 2011 I have some general comments:
- Andrej Mitrovic (2/4) Apr 06 2011 Maybe "bind" should be a better name. I'm not sure..
- bearophile (5/6) Apr 06 2011 In Python there is something similar that's named "partial":
- Andrej Mitrovic (7/7) Apr 06 2011 Well this still hasn't solved my problem. Because I shouldn't bind
- Andrej Mitrovic (2/2) Apr 06 2011 Crap, that is a horrible implementation, I didn't take into account
- Andrej Mitrovic (31/31) Apr 06 2011 Ok, enjoy this monstrosity:
- Andrej Mitrovic (2/2) Apr 06 2011 It's still wrong, the tuple is backwards. Haha, that's what I get for
- Andrej Mitrovic (33/33) Apr 06 2011 Wow, talk about enlightement. I think I've done it now:
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..
Apr 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
Apr 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.
Apr 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
Apr 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..
Apr 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
Apr 06 2011
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.
Apr 06 2011
Crap, that is a horrible implementation, I didn't take into account not binding all arguments. Be right back..
Apr 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); } } } }
Apr 06 2011
It's still wrong, the tuple is backwards. Haha, that's what I get for not unittesting.
Apr 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(); }
Apr 06 2011