www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Template currying

reply Yuxuan Shui <yshuiv7 gmail.com> writes:
So I was working on a parser combinator library, where the 
combinators take parsers as template argument. It works well 
until recently I decided to change the parsers so they would take 
Ranges instead of just strings.

The combinator used to look like:

     template Comb(alias parser1, alias parser2)

Now it looks like

     template Comb(alias parser1, alias parser2, Range)

And I want to have the compile deduce the Range template 
arguments, so I don't need to change the code that uses them. But 
I found out it's hard to partially instantiate templates.

It's OK to do that at the call site, e.g. Comb!(a, b)(range) 
works without specifying the Range. But sometimes I want to alias 
the result parser so I can use it at multiple places, but

     alias new_parser = Comb!(a, b);

doesn't work.

I need either to define Comb differently:

     template Comb(alias p1, alias p2) {
       template Comb(Range) {

or not use alias:

     template new_parser(alias p1, alias p2){
       alias new_parser(Range) = Comb!(p1, p2, Range); //Something 
like this, not tested
     }

I think it would be really nice if alias can be automatically 
translated to the latter one. Or maybe we can have something like

     template Curry(alias tmpl, Args1...) {
       alias Curry(Args2...) = tmpl!(Args1~Args2); //Pseudocode
     }

in the phobos.
May 05 2016
next sibling parent reply Ed <Ed ed.de> writes:
On Thursday, 5 May 2016 at 20:17:08 UTC, Yuxuan Shui wrote:
 So I was working on a parser combinator library, where the 
 combinators take parsers as template argument. It works well 
 until recently I decided to change the parsers so they would 
 take Ranges instead of just strings.

 The combinator used to look like:

     template Comb(alias parser1, alias parser2)

 Now it looks like

     template Comb(alias parser1, alias parser2, Range)

 And I want to have the compile deduce the Range template 
 arguments, so I don't need to change the code that uses them. 
 But I found out it's hard to partially instantiate templates.

 It's OK to do that at the call site, e.g. Comb!(a, b)(range) 
 works without specifying the Range. But sometimes I want to 
 alias the result parser so I can use it at multiple places, but

     alias new_parser = Comb!(a, b);

 doesn't work.

 I need either to define Comb differently:

     template Comb(alias p1, alias p2) {
       template Comb(Range) {

 or not use alias:

     template new_parser(alias p1, alias p2){
       alias new_parser(Range) = Comb!(p1, p2, Range); 
 //Something like this, not tested
     }

 I think it would be really nice if alias can be automatically 
 translated to the latter one. Or maybe we can have something 
 like

     template Curry(alias tmpl, Args1...) {
       alias Curry(Args2...) = tmpl!(Args1~Args2); //Pseudocode
     }

 in the phobos.
It's hard to help without a minimal working example (maybe something with just the body). If you mean that "alias new_parser = Comb!(a, b);" generates an error maybe that's because the correct syntax is "alias new_parser(Range) = Comb!(a, b);" ? One issue you may encounter is that template parameter deduction (that's called IFTI I think) can fail with an alias (so partially specialized template/templatized function, etc).
May 05 2016
parent reply Yuxuan Shui <yshuiv7 gmail.com> writes:
On Thursday, 5 May 2016 at 21:54:29 UTC, Ed wrote:
 On Thursday, 5 May 2016 at 20:17:08 UTC, Yuxuan Shui wrote:
 [...]
It's hard to help without a minimal working example (maybe something with just the body). If you mean that "alias new_parser = Comb!(a, b);" generates an error maybe that's because the correct syntax is "alias new_parser(Range) = Comb!(a, b);" ? One issue you may encounter is that template parameter deduction (that's called IFTI I think) can fail with an alias (so partially specialized template/templatized function, etc).
Simple example: int a(int b, T)(T c){return 0;} It's fine to: a!1(2); But: alias A = a!1; Would fail.
May 05 2016
parent reply Ed <Ed ed.de> writes:
On Thursday, 5 May 2016 at 22:53:01 UTC, Yuxuan Shui wrote:
 On Thursday, 5 May 2016 at 21:54:29 UTC, Ed wrote:
 On Thursday, 5 May 2016 at 20:17:08 UTC, Yuxuan Shui wrote:
 [...]
It's hard to help without a minimal working example (maybe something with just the body). If you mean that "alias new_parser = Comb!(a, b);" generates an error maybe that's because the correct syntax is "alias new_parser(Range) = Comb!(a, b);" ? One issue you may encounter is that template parameter deduction (that's called IFTI I think) can fail with an alias (so partially specialized template/templatized function, etc).
Simple example: int a(int b, T)(T c){return 0;} It's fine to: a!1(2); But: alias A = a!1; Would fail.
alias aa(T) = a!(1,T); aa!ubyte(2); Your alias declaration is not correct.
May 05 2016
parent reply Yuxuan Shui <yshuiv7 gmail.com> writes:
On Thursday, 5 May 2016 at 23:12:40 UTC, Ed wrote:
 On Thursday, 5 May 2016 at 22:53:01 UTC, Yuxuan Shui wrote:
 On Thursday, 5 May 2016 at 21:54:29 UTC, Ed wrote:
 On Thursday, 5 May 2016 at 20:17:08 UTC, Yuxuan Shui wrote:
 [...]
It's hard to help without a minimal working example (maybe something with just the body). If you mean that "alias new_parser = Comb!(a, b);" generates an error maybe that's because the correct syntax is "alias new_parser(Range) = Comb!(a, b);" ? One issue you may encounter is that template parameter deduction (that's called IFTI I think) can fail with an alias (so partially specialized template/templatized function, etc).
Simple example: int a(int b, T)(T c){return 0;} It's fine to: a!1(2); But: alias A = a!1; Would fail.
alias aa(T) = a!(1,T); aa!ubyte(2); Your alias declaration is not correct.
As you can see in my first post, I know how to make this work. I just think it'd be nice if compiler can do this automatically. Anothor point is that, what if I want to use partially instantiated templates as template arguments?
May 05 2016
next sibling parent reply Yuxuan Shui <yshuiv7 gmail.com> writes:
On Thursday, 5 May 2016 at 23:19:59 UTC, Yuxuan Shui wrote:
 On Thursday, 5 May 2016 at 23:12:40 UTC, Ed wrote:
 On Thursday, 5 May 2016 at 22:53:01 UTC, Yuxuan Shui wrote:
 On Thursday, 5 May 2016 at 21:54:29 UTC, Ed wrote:
 On Thursday, 5 May 2016 at 20:17:08 UTC, Yuxuan Shui wrote:
 [...]
It's hard to help without a minimal working example (maybe something with just the body). If you mean that "alias new_parser = Comb!(a, b);" generates an error maybe that's because the correct syntax is "alias new_parser(Range) = Comb!(a, b);" ? One issue you may encounter is that template parameter deduction (that's called IFTI I think) can fail with an alias (so partially specialized template/templatized function, etc).
Simple example: int a(int b, T)(T c){return 0;} It's fine to: a!1(2); But: alias A = a!1; Would fail.
alias aa(T) = a!(1,T); aa!ubyte(2); Your alias declaration is not correct.
As you can see in my first post, I know how to make this work. I just think it'd be nice if compiler can do this automatically. Anothor point is that, what if I want to use partially instantiated templates as template arguments?
See this example: int a(alias f)(){return f(3);} int b(int z, T)(T c){return c;} void main() { a!(b!1)(); } It'd really nice if this just works, or if there's something called Curry which I can use like this: a!(Curry!(b, 1))
May 05 2016
next sibling parent reply Ed <Ed ed.de> writes:
On Thursday, 5 May 2016 at 23:33:07 UTC, Yuxuan Shui wrote:
 It'd really nice if this just works,
That's clear that you've never been stuck in the fat mud of imperative and OO programming styles. You don't realize (anymore ?) how lucky we are with D templates, compared to other languages! Maybe you come from C++, so that's not so obvious for you but with my background I'm still amused when I see people complaining about such details. ^^ Anyway, you can open a enhancement request and pray...
May 05 2016
parent reply Yuxuan Shui <yshuiv7 gmail.com> writes:
On Thursday, 5 May 2016 at 23:46:59 UTC, Ed wrote:
 On Thursday, 5 May 2016 at 23:33:07 UTC, Yuxuan Shui wrote:
 It'd really nice if this just works,
That's clear that you've never been stuck in the fat mud of imperative and OO programming styles. You don't realize (anymore ?) how lucky we are with D templates, compared to other languages! Maybe you come from C++, so that's not so obvious for you but with my background I'm still amused when I see people complaining about such details. ^^
Yes, I do appreciate the power of D, I just want it to be BETTER.
 Anyway, you can open a enhancement request and pray...
I'll do that, but I just want to see some feedback on this idea....
May 05 2016
parent Ed <Ed ed.de> writes:
On Friday, 6 May 2016 at 00:08:01 UTC, Yuxuan Shui wrote:
 On Thursday, 5 May 2016 at 23:46:59 UTC, Ed wrote:
 On Thursday, 5 May 2016 at 23:33:07 UTC, Yuxuan Shui wrote:
 It'd really nice if this just works,
That's clear that you've never been stuck in the fat mud of imperative and OO programming styles. You don't realize (anymore ?) how lucky we are with D templates, compared to other languages! Maybe you come from C++, so that's not so obvious for you but with my background I'm still amused when I see people complaining about such details. ^^
Yes, I do appreciate the power of D, I just want it to be BETTER.
 Anyway, you can open a enhancement request and pray...
I'll do that, but I just want to see some feedback on this idea....
Sorry, I don't know why I thought this thread was on d.learn, I didn't get this was a general discussion.
May 05 2016
prev sibling parent reply Yuxuan Shui <yshuiv7 gmail.com> writes:
On Thursday, 5 May 2016 at 23:33:07 UTC, Yuxuan Shui wrote:
 On Thursday, 5 May 2016 at 23:19:59 UTC, Yuxuan Shui wrote:
 On Thursday, 5 May 2016 at 23:12:40 UTC, Ed wrote:
 On Thursday, 5 May 2016 at 22:53:01 UTC, Yuxuan Shui wrote:
 [...]
alias aa(T) = a!(1,T); aa!ubyte(2); Your alias declaration is not correct.
As you can see in my first post, I know how to make this work. I just think it'd be nice if compiler can do this automatically. Anothor point is that, what if I want to use partially instantiated templates as template arguments?
See this example: int a(alias f)(){return f(3);} int b(int z, T)(T c){return c;} void main() { a!(b!1)(); } It'd really nice if this just works, or if there's something called Curry which I can use like this: a!(Curry!(b, 1))
Wait, I just realized that this example works in 2.071, but not in 2.068.2. What has changed?
May 05 2016
parent reply Yuxuan Shui <yshuiv7 gmail.com> writes:
On Friday, 6 May 2016 at 06:18:22 UTC, Yuxuan Shui wrote:
 On Thursday, 5 May 2016 at 23:33:07 UTC, Yuxuan Shui wrote:
 On Thursday, 5 May 2016 at 23:19:59 UTC, Yuxuan Shui wrote:
 [...]
See this example: int a(alias f)(){return f(3);} int b(int z, T)(T c){return c;} void main() { a!(b!1)(); } It'd really nice if this just works, or if there's something called Curry which I can use like this: a!(Curry!(b, 1))
Wait, I just realized that this example works in 2.071, but not in 2.068.2. What has changed?
Apply{Left, Right} is add in 2.071 as well, and I didn't see them mentioned in the ChangLog...
May 05 2016
parent reply Yuxuan Shui <yshuiv7 gmail.com> writes:
On Friday, 6 May 2016 at 06:26:14 UTC, Yuxuan Shui wrote:
 On Friday, 6 May 2016 at 06:18:22 UTC, Yuxuan Shui wrote:
 On Thursday, 5 May 2016 at 23:33:07 UTC, Yuxuan Shui wrote:
 On Thursday, 5 May 2016 at 23:19:59 UTC, Yuxuan Shui wrote:
 [...]
See this example: int a(alias f)(){return f(3);} int b(int z, T)(T c){return c;} void main() { a!(b!1)(); } It'd really nice if this just works, or if there's something called Curry which I can use like this: a!(Curry!(b, 1))
Wait, I just realized that this example works in 2.071, but not in 2.068.2. What has changed?
Apply{Left, Right} is add in 2.071 as well, and I didn't see them mentioned in the ChangLog...
Oh, sorry, that doesn't work. My mistake. And ApplyLeft doesn't work for that example either (I thought it would). Looks like it's a bit more difficult to implement Curry!() than I thought.
May 05 2016
parent Yuxuan Shui <yshuiv7 gmail.com> writes:
On Friday, 6 May 2016 at 06:30:27 UTC, Yuxuan Shui wrote:
 On Friday, 6 May 2016 at 06:26:14 UTC, Yuxuan Shui wrote:
 On Friday, 6 May 2016 at 06:18:22 UTC, Yuxuan Shui wrote:
 On Thursday, 5 May 2016 at 23:33:07 UTC, Yuxuan Shui wrote:
     [...]
Wait, I just realized that this example works in 2.071, but not in 2.068.2. What has changed?
Apply{Left, Right} is add in 2.071 as well, and I didn't see them mentioned in the ChangLog...
Oh, sorry, that doesn't work. My mistake. And ApplyLeft doesn't work for that example either (I thought it would). Looks like it's a bit more difficult to implement Curry!() than I thought.
I figured it out, here is a prototype of Curry: template Curry(alias tmpl, Left...) { auto Curry(Right...)(Right r) { return tmpl!Left(r); } }
May 05 2016
prev sibling parent reply Ed <Ed ed.de> writes:
On Thursday, 5 May 2016 at 23:19:59 UTC, Yuxuan Shui wrote:
 On Thursday, 5 May 2016 at 23:12:40 UTC, Ed wrote:
 On Thursday, 5 May 2016 at 22:53:01 UTC, Yuxuan Shui wrote:
 On Thursday, 5 May 2016 at 21:54:29 UTC, Ed wrote:
 On Thursday, 5 May 2016 at 20:17:08 UTC, Yuxuan Shui wrote:
 [...]
It's hard to help without a minimal working example (maybe something with just the body). If you mean that "alias new_parser = Comb!(a, b);" generates an error maybe that's because the correct syntax is "alias new_parser(Range) = Comb!(a, b);" ? One issue you may encounter is that template parameter deduction (that's called IFTI I think) can fail with an alias (so partially specialized template/templatized function, etc).
Simple example: int a(int b, T)(T c){return 0;} It's fine to: a!1(2); But: alias A = a!1; Would fail.
alias aa(T) = a!(1,T); aa!ubyte(2); Your alias declaration is not correct.
As you can see in my first post, I know how to make this work. I just think it'd be nice if compiler can do this automatically. Anothor point is that, what if I want to use partially instantiated templates as template arguments?
My bad, I didn't read carefully "or not use alias:". With alias template parameter you can pass template: ------ import std.stdio; template Foo(T,U){ T pop(){return T.max;}} alias Partial(U) = Foo!(U, string); auto bar(alias Whatever)() { alias instance = Whatever!int; return instance.pop; } void main(string[] args) { writeln(bar!(Partial)()); } ------ for example.
May 05 2016
parent Yuxuan Shui <yshuiv7 gmail.com> writes:
On Thursday, 5 May 2016 at 23:38:38 UTC, Ed wrote:
 On Thursday, 5 May 2016 at 23:19:59 UTC, Yuxuan Shui wrote:
 On Thursday, 5 May 2016 at 23:12:40 UTC, Ed wrote:
 On Thursday, 5 May 2016 at 22:53:01 UTC, Yuxuan Shui wrote:
 [...]
alias aa(T) = a!(1,T); aa!ubyte(2); Your alias declaration is not correct.
As you can see in my first post, I know how to make this work. I just think it'd be nice if compiler can do this automatically. Anothor point is that, what if I want to use partially instantiated templates as template arguments?
My bad, I didn't read carefully "or not use alias:". With alias template parameter you can pass template: ------ import std.stdio; template Foo(T,U){ T pop(){return T.max;}} alias Partial(U) = Foo!(U, string); auto bar(alias Whatever)() { alias instance = Whatever!int; return instance.pop; } void main(string[] args) { writeln(bar!(Partial)()); } ------
Right, Partial!() works. I just want something more generic, like the Curry I proposed. And I still think let the compiler do it is a good idea, because this could removes special cases in template arguments deduction
May 05 2016
prev sibling parent ZombineDev <petar.p.kirov gmail.com> writes:
On Thursday, 5 May 2016 at 20:17:08 UTC, Yuxuan Shui wrote:
 So I was working on a parser combinator library, where the 
 combinators take parsers as template argument. It works well 
 until recently I decided to change the parsers so they would 
 take Ranges instead of just strings.

 The combinator used to look like:

     template Comb(alias parser1, alias parser2)

 Now it looks like

     template Comb(alias parser1, alias parser2, Range)

 And I want to have the compile deduce the Range template 
 arguments, so I don't need to change the code that uses them. 
 But I found out it's hard to partially instantiate templates.

 It's OK to do that at the call site, e.g. Comb!(a, b)(range) 
 works without specifying the Range. But sometimes I want to 
 alias the result parser so I can use it at multiple places, but

     alias new_parser = Comb!(a, b);

 doesn't work.

 I need either to define Comb differently:

     template Comb(alias p1, alias p2) {
       template Comb(Range) {

 or not use alias:

     template new_parser(alias p1, alias p2){
       alias new_parser(Range) = Comb!(p1, p2, Range); 
 //Something like this, not tested
     }

 I think it would be really nice if alias can be automatically 
 translated to the latter one. Or maybe we can have something 
 like

     template Curry(alias tmpl, Args1...) {
       alias Curry(Args2...) = tmpl!(Args1~Args2); //Pseudocode
     }

 in the phobos.
alias can automatically introduce template arguments only for function literals: alias add = (a, b) => a + b; add has two implicit template arguments: auto sum = add(4, 3.17); deduced to int and double in the case above. Actually the alias add refers to the symbol of an automatically generated template: alias add = _add_generated; template _add_generated(T1, T2) { auto _add_generated(T1 a, T2 b) { return a + b; } } The closest thing to getting the compiler to generate something like the above template is ApplyLeft/ApplyRight from std.meta:
May 05 2016