digitalmars.D - Partial template application
- bearophile (65/65) Jan 31 2011 Functional languages often have built-in partial function application:
- Simen kjaeraas (6/26) Jan 31 2011 dranges has something like this:
- Andrej Mitrovic (9/9) Jan 31 2011 Isn't it possible to unify functions which work on compile-time and
- bearophile (13/19) Jan 31 2011 This is currently not possible, a static curry needs compile-time argume...
- Andrej Mitrovic (24/31) Jan 31 2011 Well I do think there should be a difference between compile time and
Functional languages often have built-in partial function application: http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application D doesn't have this feature built-in despite it can't break C compatibility, maybe because it's a lot of work to implement, maybe because it is seen as bug-prone, or maybe just because Walter was/is not interested in it. So in D you do it using std.functional.curry (I think this is a partial application more than a currying, so I am not sure this is the best name): int fun(int a, int b) { return a + b; } alias curry!(fun, 5) fun5; assert(fun5(6) == 11); Few hours ago in D.learn Simen Kjaeraas has shown a small D2 program that uses nested templates to allow template partial application: import std.typecons, std.functional, std.array; template optArg(alias pred) { template optArg(alias fn) { auto optArg(Range)(Range r) { alias binaryFun!pred predicate; alias unaryFun!fn func; auto result = tuple(r.front, func(r.front)); foreach (e; r) { auto tmp = func(e); if (predicate(e, result[1])) result = tuple(e, tmp); } return result; } } } void main() { alias optArg!"a < b" minArg; alias minArg!"a" foo; assert(foo([5, 2, 1, 3]) == tuple(1, 1)); } I'd like a new template feature in D, automatic partial template application. It allows to simplify that code like this (untested): import std.typecons, std.functional, std.array; auto optArg(alias pred, alias fn, Range)(Range r) { alias binaryFun!pred predicate; alias unaryFun!fn func; auto result = tuple(r.front, func(r.front)); foreach (e; r) { auto tmp = func(e); if (predicate(e, result[1])) result = tuple(e, tmp); } } void main() { alias optArg!"a < b" minArg; alias minArg!"a" foo; assert(foo([5, 2, 1, 3]) == tuple(1, 1)); } If (as usual) you don't want to implement this as a new D feature, I presume something like a PartialTemplate/StaticCurry/StaticPartialApplication is writeable in the standard library: import std.typecons, std.functional, std.array; auto optArg(alias pred, alias fn, Range)(Range r) { alias binaryFun!pred predicate; alias unaryFun!fn func; auto result = tuple(r.front, func(r.front)); foreach (e; r) { auto tmp = func(e); if (predicate(e, result[1])) result = tuple(e, tmp); } } void main() { alias PartialTemplate!(optArg, "a < b") minArg; alias PartialTemplate!(minArg, "a") foo; assert(foo([5, 2, 1, 3]) == tuple(1, 1)); } Bye, bearophile
Jan 31 2011
bearophile <bearophileHUGS lycos.com> wrote:If (as usual) you don't want to implement this as a new D feature, I presume something like a PartialTemplate/StaticCurry/StaticPartialApplication is writeable in the standard library: import std.typecons, std.functional, std.array; auto optArg(alias pred, alias fn, Range)(Range r) { alias binaryFun!pred predicate; alias unaryFun!fn func; auto result = tuple(r.front, func(r.front)); foreach (e; r) { auto tmp = func(e); if (predicate(e, result[1])) result = tuple(e, tmp); } } void main() { alias PartialTemplate!(optArg, "a < b") minArg; alias PartialTemplate!(minArg, "a") foo; assert(foo([5, 2, 1, 3]) == tuple(1, 1)); }dranges has something like this: http://svn.dsource.org/projects/dranges/trunk/dranges/docs/templates.html see CurryTemplate -- Simen
Jan 31 2011
Isn't it possible to unify functions which work on compile-time and run-time arguments? What I mean is, if curry detects that you're currying a compile-time argument against a template, then it should do what your PartialTemplate/StaticCurry would do. It seems odd having to create 'static' counterparts to functions in Phobos. So far I only know of staticIndexOf and staticMap. But adding more would seem like duplicating the effort and creating a sort of std.staticAlgorithm
Jan 31 2011
Andrej Mitrovic:What I mean is, if curry detects that you're currying a compile-time argument against a template, then it should do what your PartialTemplate/StaticCurry would do.This is currently not possible, a static curry needs compile-time arguments, so they need to specified as template arguments (with the bang !), while the normal curry is supposed to work with run-time values too. Walter has tried to unify the two, using a syntax like: void foo(int x, static int y, int z) {} That's equivalent to: void foo(int y)(int x, int z) {} But the legend says he has found unspecified implementation difficulties, so the idea was abandoned. One purpose of D design is to avoid excessive compiler complexity. ----------------------- Simen kjaeraas:dranges has something like this: http://svn.dsource.org/projects/dranges/trunk/dranges/docs/templates.html see CurryTemplateThank you for the link. This looks like a true currying, instead of a partial application like std.functional.curry. I suggest to add CurryTemplate to Phobos2 while we wait forever for templates to be curried on default :-) Bye, bearophile
Jan 31 2011
On 1/31/11, bearophile <bearophileHUGS lycos.com> wrote:Walter has tried to unify the two, using a syntax like: void foo(int x, static int y, int z) {} That's equivalent to: void foo(int y)(int x, int z) {} But the legend says he has found unspecified implementation difficulties, so the idea was abandoned. One purpose of D design is to avoid excessive compiler complexity.Well I do think there should be a difference between compile time and runtime arguments, so I'd keep the current syntax rather than mix the two. Perhaps D3 could have a form of static expressions: import std.typecons, std.functional, std.array; auto optArg(alias pred, alias fn, Range)(Range r) { // same as before } void main() { alias static optArg!"a < b" minArg; alias static minArg!"a" foo; assert(foo([5, 2, 1, 3]) == tuple(1, 1)); } and then we could have: import std.stdio, std.typetuple, std.algorithm, std.traits, std.range; void main() { int[] arr1 = [ 1, 2, 3, 4 ]; int[] arr2 = [ 5, 6 ]; auto squares = map!("a * a")(chain(arr1, arr2)); //~ alias staticMap!(Unqual, int, const int, immutable int) T; alias static map!(Unqual, int, const int, immutable int) T; } I'm not sure how that would work, I'm just throwing ideas in the air. :)
Jan 31 2011