www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Type programming game

reply Stefan Koch <uplink.coder googlemail.com> writes:
Hi,

just now I came up with a nice game.

Write a template/function takes a sequence of types, and 
"returns" a string.
Whenever the same type appears twice in the sequence directly 
after the previous occurrence,
append ("double " ~ name_of_type) to the string.
Whenever it appears three times, append ("triple " ~ 
name_of_type).

So (int, int, uint, uint, uint) would return "double int triple 
uint")
Or (char, char, wchar, dchar, dchar) would return "double char 
double dchar"

I am looking forward to what you come up with.

After a few submissions have been made I will post my type 
function, which fulfills this task.

Have a good day,

Stefan
Oct 10 2020
next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 11.10.20 01:42, Stefan Koch wrote:
 
 Write a template/function takes a sequence of types, and "returns" a 
 string.
 Whenever the same type appears twice in the sequence directly after the 
 previous occurrence,
 append ("double " ~ name_of_type) to the string.
 Whenever it appears three times, append ("triple " ~ name_of_type).
 
 So (int, int, uint, uint, uint) would return "double int triple uint")
 Or (char, char, wchar, dchar, dchar) would return "double char double 
 dchar"
I guess the canonical solution is something like this: alias Seq(T...)=T; template Group(T...){ static if(T.length==0) alias Group=Seq!(); else static if(T.length==1) alias Group=Seq!(1,T[0]); else{ alias R=Group!(T[1..$]); static if(is(T[0]==R[1])) alias Group=Seq!(R[0]+1,R[1..$]); else alias Group=Seq!(1,T[0],R); } } template solve(T...){ template rec(G...){ static if(G.length==0) enum rec=""; else{ enum r=rec!(G[2..$]); enum s=G[1].stringof~(r.length?" ":"")~r; static if(G[0]==2) enum rec="double "~s; else static if(G[0]==3) enum rec="triple "~s; else enum rec=r; } } alias solve=rec!(Group!T); } static assert(solve!(int,int,uint,uint,uint)=="double int triple uint"); static assert(solve!(char,char,wchar,dchar,dchar)=="double char double dchar");
Oct 10 2020
parent Stefan Koch <uplink.coder googlemail.com> writes:
On Sunday, 11 October 2020 at 00:47:26 UTC, Timon Gehr wrote:
 I guess the canonical solution is something like this:

 alias Seq(T...)=T;
 template Group(T...){
     static if(T.length==0) alias Group=Seq!();
     else static if(T.length==1) alias Group=Seq!(1,T[0]);
     else{
         alias R=Group!(T[1..$]);
         static if(is(T[0]==R[1])) alias 
 Group=Seq!(R[0]+1,R[1..$]);
         else alias Group=Seq!(1,T[0],R);
     }
 }
 template solve(T...){
     template rec(G...){
         static if(G.length==0) enum rec="";
         else{
             enum r=rec!(G[2..$]);
             enum s=G[1].stringof~(r.length?" ":"")~r;
             static if(G[0]==2) enum rec="double "~s;
             else static if(G[0]==3) enum rec="triple "~s;
             else enum rec=r;
         }
     }
     alias solve=rec!(Group!T);
 }

 static assert(solve!(int,int,uint,uint,uint)=="double int 
 triple uint");
 static assert(solve!(char,char,wchar,dchar,dchar)=="double char 
 double dchar");
I am thoroughly impressed. ... also I found a bug in the type-function implementation which will integer-promote the type char into int ... and therefore fail the testcases I set myself. The type-function solution will come tomorrow (since I don't post code that doesn't actually run).
Oct 10 2020
prev sibling next sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Saturday, 10 October 2020 at 23:42:46 UTC, Stefan Koch wrote:
 After a few submissions have been made I will post my type 
 function, which fulfills this task.
Surely you know by now what I'm going to say... just write a normal function. module typegame.solution; string easy(T...)() { string result; // I separate out the display name from the seen name // since you might pass a.Foo and b.Foo and want it // differentiated in comparison but both displayed "Foo" string lastDisplay; string lastSeen; int repetitionCount; void finish() { if(repetitionCount != 2 && repetitionCount != 3) return; if(result.length) result ~= " "; if(repetitionCount == 2) result ~= "double "; else result ~= "triple "; result ~= lastDisplay; } foreach(t; T) { if(t.mangleof == lastSeen) { repetitionCount++; } else { finish(); lastSeen = t.mangleof; lastDisplay = t.stringof; repetitionCount = 1; } } finish(); return result; } pragma(msg, easy!(int, int, uint, uint, uint)); pragma(msg, easy!(char, char, wchar, dchar, dchar));
Oct 10 2020
parent reply Stefan Koch <uplink.coder googlemail.com> writes:
On Sunday, 11 October 2020 at 01:08:46 UTC, Adam D. Ruppe wrote:
 On Saturday, 10 October 2020 at 23:42:46 UTC, Stefan Koch wrote:
 After a few submissions have been made I will post my type 
 function, which fulfills this task.
Surely you know by now what I'm going to say... just write a normal function. module typegame.solution; string easy(T...)() { string result; // I separate out the display name from the seen name // since you might pass a.Foo and b.Foo and want it // differentiated in comparison but both displayed "Foo" string lastDisplay; string lastSeen; int repetitionCount; void finish() { if(repetitionCount != 2 && repetitionCount != 3) return; if(result.length) result ~= " "; if(repetitionCount == 2) result ~= "double "; else result ~= "triple "; result ~= lastDisplay; } foreach(t; T) { if(t.mangleof == lastSeen) { repetitionCount++; } else { finish(); lastSeen = t.mangleof; lastDisplay = t.stringof; repetitionCount = 1; } } finish(); return result; } pragma(msg, easy!(int, int, uint, uint, uint)); pragma(msg, easy!(char, char, wchar, dchar, dchar));
This is a neat solution. Congratulations Adam.
Oct 10 2020
parent Patrick Schluter <Patrick.Schluter bbox.fr> writes:
On Sunday, 11 October 2020 at 01:16:29 UTC, Stefan Koch wrote:
 On Sunday, 11 October 2020 at 01:08:46 UTC, Adam D. Ruppe wrote:
 [...]
This is a neat solution. Congratulations Adam.
It has only the disadvantage of generating code of a new function for each instanciation, does it not?
Oct 11 2020
prev sibling parent reply Basile B. <b2.temp gmx.com> writes:
On Saturday, 10 October 2020 at 23:42:46 UTC, Stefan Koch wrote:
 Hi,

 just now I came up with a nice game.

 Write a template/function takes a sequence of types, and 
 "returns" a string.
 Whenever the same type appears twice in the sequence directly 
 after the previous occurrence,
 append ("double " ~ name_of_type) to the string.
 Whenever it appears three times, append ("triple " ~ 
 name_of_type).

 So (int, int, uint, uint, uint) would return "double int triple 
 uint")
 Or (char, char, wchar, dchar, dchar) would return "double char 
 double dchar"

 I am looking forward to what you come up with.

 After a few submissions have been made I will post my type 
 function, which fulfills this task.

 Have a good day,

 Stefan
fully CTFE + using a map to solve uniquness. Naive, longish, but easy to understand I'd say as self-criticism... but I suppose that the final goal of this game is to show us an astonishing TF solution ;) --- import std.algorithm; string solveByMapping(T...)() { string[] uniques; size_t[] indexes; size_t[] count; string result; static foreach (TT; T) { if (!uniques.canFind(TT.stringof)) uniques ~= TT.stringof; indexes ~= uniques.length - 1; } count.length = uniques.length; static foreach (i, TT; T) { count[indexes[i]] += 1; } foreach(ref c; count) { if (c != 2 && c != 3) c = 0; } foreach(i, c; count) { if (!c) continue; result ~= (c == 3) ? " triple " : " twice "; result ~= uniques[i]; } return result[1..$]; } static assert (solveByMapping!(int, int, uint, uint, uint) == "twice int triple uint"); static assert (solveByMapping!(int, int, uint) == "twice int"); static assert (solveByMapping!(float, float, int, int, uint) == "twice float twice int"); ---
Oct 11 2020
parent reply Stefan Koch <uplink.coder googlemail.com> writes:
On Sunday, 11 October 2020 at 09:31:43 UTC, Basile B. wrote:
 On Saturday, 10 October 2020 at 23:42:46 UTC, Stefan Koch wrote:
 Hi,

 just now I came up with a nice game.

 Write a template/function takes a sequence of types, and 
 "returns" a string.
 Whenever the same type appears twice in the sequence directly 
 after the previous occurrence,
 append ("double " ~ name_of_type) to the string.
 Whenever it appears three times, append ("triple " ~ 
 name_of_type).

 So (int, int, uint, uint, uint) would return "double int 
 triple uint")
 Or (char, char, wchar, dchar, dchar) would return "double char 
 double dchar"

 I am looking forward to what you come up with.

 After a few submissions have been made I will post my type 
 function, which fulfills this task.

 Have a good day,

 Stefan
fully CTFE + using a map to solve uniquness. Naive, longish, but easy to understand I'd say as self-criticism... but I suppose that the final goal of this game is to show us an astonishing TF solution ;) --- import std.algorithm; string solveByMapping(T...)() { string[] uniques; size_t[] indexes; size_t[] count; string result; static foreach (TT; T) { if (!uniques.canFind(TT.stringof)) uniques ~= TT.stringof; indexes ~= uniques.length - 1; } count.length = uniques.length; static foreach (i, TT; T) { count[indexes[i]] += 1; } foreach(ref c; count) { if (c != 2 && c != 3) c = 0; } foreach(i, c; count) { if (!c) continue; result ~= (c == 3) ? " triple " : " twice "; result ~= uniques[i]; } return result[1..$]; } static assert (solveByMapping!(int, int, uint, uint, uint) == "twice int triple uint"); static assert (solveByMapping!(int, int, uint) == "twice int"); static assert (solveByMapping!(float, float, int, int, uint) == "twice float twice int"); ---
Thanks for attending the game! And you are right the type function version which works now looks like this. It should not be astonishing ;) --- alias type = __type; string double_triple(type[] types...) { string result; type current; uint count; foreach(i, t;types) { if (is(current == t)) { count++; // if the last one didn't change we need to eval the count if (i == types.length - 1) goto Leval_count; } else { Leval_count: if (count == 2) { result ~= "double " ~ __traits(identifier, current) ~ " "; } else if (count == 3) { result ~= "triple " ~ __traits(identifier, current) ~ " "; } current = t; count = 1; } } return result[0 .. $-1]; } static assert(double_triple(int,int,uint,uint,uint) == "double int triple uint"); static assert(double_triple(char,char,wchar,dchar,dchar) == "double char double dchar"); static assert(double_triple(double, double, float, float, float) == "double double triple float"); --- In continuation I will post benchmarks of all 4 (or more of others come in) solutions on longer type sequences.
Oct 11 2020
next sibling parent Basile B. <b2.temp gmx.com> writes:
On Sunday, 11 October 2020 at 10:46:00 UTC, Stefan Koch wrote:
 On Sunday, 11 October 2020 at 09:31:43 UTC, Basile B. wrote:
 On Saturday, 10 October 2020 at 23:42:46 UTC, Stefan Koch
In continuation I will post benchmarks of all 4 (or more of others come in) solutions on longer type sequences.
I haven't seen it directly but in my solution the loop that set `c` to `0` can be removed.
Oct 11 2020
prev sibling parent reply claptrap <clap trap.com> writes:
On Sunday, 11 October 2020 at 10:46:00 UTC, Stefan Koch wrote:
 On Sunday, 11 October 2020 at 09:31:43 UTC, Basile B. wrote:
 On Saturday, 10 October 2020 at 23:42:46 UTC, Stefan Koch 
 wrote:
 Hi,
static assert(double_triple(int,int,uint,uint,uint) == "double int triple uint"); static assert(double_triple(char,char,wchar,dchar,dchar) == "double char double dchar"); static assert(double_triple(double, double, float, float, float) == "double double triple float"); --- In continuation I will post benchmarks of all 4 (or more of others come in) solutions on longer type sequences.
Maybe this type function version will work string double_triple(type[] types...) { string result; uint subidx = 0; foreach(i, t; types) { if ((i == types.length-1) || is(types[i] != types[i+1])) { result ~= ["","double","triple","quadruple"][i-subidx] ~ __traits(identifier, t) ~ " "; subidx = i+1; } } return result; }
Oct 12 2020
next sibling parent Stefan Koch <uplink.coder googlemail.com> writes:
On Monday, 12 October 2020 at 14:04:56 UTC, claptrap wrote:
 On Sunday, 11 October 2020 at 10:46:00 UTC, Stefan Koch wrote:
 On Sunday, 11 October 2020 at 09:31:43 UTC, Basile B. wrote:
 On Saturday, 10 October 2020 at 23:42:46 UTC, Stefan Koch 
 wrote:
 Hi,
static assert(double_triple(int,int,uint,uint,uint) == "double int triple uint"); static assert(double_triple(char,char,wchar,dchar,dchar) == "double char double dchar"); static assert(double_triple(double, double, float, float, float) == "double double triple float"); --- In continuation I will post benchmarks of all 4 (or more of others come in) solutions on longer type sequences.
Maybe this type function version will work string double_triple(type[] types...) { string result; uint subidx = 0; foreach(i, t; types) { if ((i == types.length-1) || is(types[i] != types[i+1])) { result ~= ["","double","triple","quadruple"][i-subidx] ~ __traits(identifier, t) ~ " "; subidx = i+1; } } return result; }
Thanks for you submission. You helped me to find a bug within the TF implementation. For some reason indexing of types[] that does not happen automatically in the foreach doesn't work. (Which is really strange because under the hood it should use the same code...) There is one mistake in your code which I would like to correct. is-expressions cannot use != you have to state it as:
 (!is(types[i] ==  types[i+1]))
Other than that the code should run well, as soon as the bug with the indexing of __type arrays is fixed.
Oct 13 2020
prev sibling parent reply Stefan Koch <uplink.coder googlemail.com> writes:
On Monday, 12 October 2020 at 14:04:56 UTC, claptrap wrote:
 Maybe this type function version will work

 string double_triple(type[] types...)
 {
     string result;
     uint subidx = 0;

     foreach(i, t; types)
     {
         if ((i == types.length-1) ||  is(types[i] != 
 types[i+1]))
         {
             result ~= 
 ["","double","triple","quadruple"][i-subidx]
                ~ __traits(identifier, t) ~ " ";
             subidx = i+1;
         }
     }
     return result;
 }
I fixed your version to work around the bugs in type functions. (As of git commit 1652c194870f9c66161888425a9cdf01db8187f6 (in https://github.com/UplinkCoder/dmd/tree/talias_master)) Here is it fixed: --- alias type = __type; string double_triple(type[] types...) { string result; size_t subidx = 0; foreach(i, t; types) { // for some reason using type[idx] will only work within an assign exp // this still to be fixed auto t2 = (i == types.length-1) ? cast(type)type.init : types[i+1]; if (!is(t2 == t)) // this works because if t2 is type.init it will eval to false; { if (i-subidx) { result ~= ["","double","triple","quadruple"][i-subidx] ~ " " ~ __traits(identifier, t) ~ " "; } subidx = i+1; } } return result[0 .. $-1]; } static assert(double_triple(char,char,wchar,dchar,dchar) == "double char double dchar"); static assert(double_triple(char,char,wchar,dchar,dchar, dchar) == "double char triple dchar"); ---
Oct 13 2020
parent reply claptrap <clap trap.com> writes:
On Tuesday, 13 October 2020 at 14:43:23 UTC, Stefan Koch wrote:
 On Monday, 12 October 2020 at 14:04:56 UTC, claptrap wrote:
 I fixed your version to work around the bugs in type functions.
 (As of git commit 1652c194870f9c66161888425a9cdf01db8187f6 (in 
 https://github.com/UplinkCoder/dmd/tree/talias_master))

 Here is it fixed:
 ---

 alias type = __type;
 string double_triple(type[] types...)
 {
     string result;
     size_t subidx = 0;

     foreach(i, t; types)
     {
         // for some reason using type[idx] will only work 
 within an assign exp
         // this still to be fixed
         auto t2 = (i == types.length-1) ? cast(type)type.init : 
 types[i+1];
         if (!is(t2 == t)) // this works because if t2 is 
 type.init it will eval to false;
         {
             if (i-subidx)
             {
                 result ~= 
 ["","double","triple","quadruple"][i-subidx]
                     ~ " " ~ __traits(identifier, t) ~ " ";
             }

            subidx = i+1;
         }
     }
     return result[0 .. $-1];
 }

 static assert(double_triple(char,char,wchar,dchar,dchar) == 
 "double char double dchar");
 static assert(double_triple(char,char,wchar,dchar,dchar, dchar) 
 == "double char triple dchar");
 ---
Yeah not as concise as it could be, but I assume eventually type[idx] will work outside assign expressions?
Oct 13 2020
parent reply Stefan Koch <uplink.coder googlemail.com> writes:
On Wednesday, 14 October 2020 at 00:11:37 UTC, claptrap wrote:
 On Tuesday, 13 October 2020 at 14:43:23 UTC, Stefan Koch wrote:
 On Monday, 12 October 2020 at 14:04:56 UTC, claptrap wrote:
 I fixed your version to work around the bugs in type functions.
 [...]
Yeah not as concise as it could be, but I assume eventually type[idx] will work outside assign expressions?
Yes of course.
Oct 14 2020
next sibling parent reply Basile B. <b2temp gmx.com> writes:
On Wednesday, 14 October 2020 at 11:14:34 UTC, Stefan Koch wrote:
 On Wednesday, 14 October 2020 at 00:11:37 UTC, claptrap wrote:
 On Tuesday, 13 October 2020 at 14:43:23 UTC, Stefan Koch wrote:
 On Monday, 12 October 2020 at 14:04:56 UTC, claptrap wrote:
 I fixed your version to work around the bugs in type 
 functions.
 [...]
Yeah not as concise as it could be, but I assume eventually type[idx] will work outside assign expressions?
Yes of course.
So what's up with the benchmark you mentioned ? With four entries + your TF version we can have a podium now.
Oct 17 2020
parent reply Stefan Koch <uplink.coder googlemail.com> writes:
On Saturday, 17 October 2020 at 12:46:44 UTC, Basile B. wrote:
 On Wednesday, 14 October 2020 at 11:14:34 UTC, Stefan Koch 
 wrote:
 On Wednesday, 14 October 2020 at 00:11:37 UTC, claptrap wrote:
 On Tuesday, 13 October 2020 at 14:43:23 UTC, Stefan Koch 
 wrote:
 On Monday, 12 October 2020 at 14:04:56 UTC, claptrap wrote:
 I fixed your version to work around the bugs in type 
 functions.
 [...]
Yeah not as concise as it could be, but I assume eventually type[idx] will work outside assign expressions?
Yes of course.
So what's up with the benchmark you mentioned ? With four entries + your TF version we can have a podium now.
Coming up. Fixes to accommodate claptrap's original version have to be made first.
Oct 17 2020
parent reply Basile B. <b2temp gmx.com> writes:
On Saturday, 17 October 2020 at 12:53:44 UTC, Stefan Koch wrote:
 On Saturday, 17 October 2020 at 12:46:44 UTC, Basile B. wrote:
 On Wednesday, 14 October 2020 at 11:14:34 UTC, Stefan Koch 
 wrote:
 On Wednesday, 14 October 2020 at 00:11:37 UTC, claptrap wrote:
 On Tuesday, 13 October 2020 at 14:43:23 UTC, Stefan Koch 
 wrote:
 On Monday, 12 October 2020 at 14:04:56 UTC, claptrap wrote:
 I fixed your version to work around the bugs in type 
 functions.
 [...]
Yeah not as concise as it could be, but I assume eventually type[idx] will work outside assign expressions?
Yes of course.
So what's up with the benchmark you mentioned ? With four entries + your TF version we can have a podium now.
Coming up. Fixes to accommodate claptrap's original version have to be made first.
yeah but his version is a TF one BTW. Maybe I missed the point, weren't we supposed to propose a version based on CTFE+template only ?
Oct 17 2020
parent reply Stefan Koch <uplink.coder googlemail.com> writes:
On Saturday, 17 October 2020 at 12:59:19 UTC, Basile B. wrote:
 On Saturday, 17 October 2020 at 12:53:44 UTC, Stefan Koch wrote:
 On Saturday, 17 October 2020 at 12:46:44 UTC, Basile B. wrote:
 On Wednesday, 14 October 2020 at 11:14:34 UTC, Stefan Koch 
 wrote:
 On Wednesday, 14 October 2020 at 00:11:37 UTC, claptrap 
 wrote:
 [...]
Yes of course.
So what's up with the benchmark you mentioned ? With four entries + your TF version we can have a podium now.
Coming up. Fixes to accommodate claptrap's original version have to be made first.
yeah but his version is a TF one BTW. Maybe I missed the point, weren't we supposed to propose a version based on CTFE+template only ?
You can propose a version using anything that you think will work. As long as I can get a version of DMD that can compile it.
Oct 17 2020
parent Basile B. <b2.temp gmx.com> writes:
On Saturday, 17 October 2020 at 13:37:20 UTC, Stefan Koch wrote:
 On Saturday, 17 October 2020 at 12:59:19 UTC, Basile B. wrote:
 On Saturday, 17 October 2020 at 12:53:44 UTC, Stefan Koch 
 wrote:
 On Saturday, 17 October 2020 at 12:46:44 UTC, Basile B. wrote:
 On Wednesday, 14 October 2020 at 11:14:34 UTC, Stefan Koch 
 wrote:
 On Wednesday, 14 October 2020 at 00:11:37 UTC, claptrap 
 wrote:
 [...]
Yes of course.
So what's up with the benchmark you mentioned ? With four entries + your TF version we can have a podium now.
Coming up. Fixes to accommodate claptrap's original version have to be made first.
yeah but his version is a TF one BTW. Maybe I missed the point, weren't we supposed to propose a version based on CTFE+template only ?
You can propose a version using anything that you think will work. As long as I can get a version of DMD that can compile it.
Actually, and even it's sure that TF version will be faster, I could propose a second version of my entry since the bounds of the dynamic array I use are tied to the length of the variadic template arg... So I can use static arrays and a variable to give the upper bound in the array of unique types. Not sure if it is worth ;)
Oct 17 2020
prev sibling parent Stefan Koch <uplink.coder googlemail.com> writes:
On Wednesday, 14 October 2020 at 11:14:34 UTC, Stefan Koch wrote:
 On Wednesday, 14 October 2020 at 00:11:37 UTC, claptrap wrote:
 On Tuesday, 13 October 2020 at 14:43:23 UTC, Stefan Koch wrote:
 On Monday, 12 October 2020 at 14:04:56 UTC, claptrap wrote:
 I fixed your version to work around the bugs in type 
 functions.
 [...]
Yeah not as concise as it could be, but I assume eventually type[idx] will work outside assign expressions?
Yes of course.
So it turns out not to be the type-array[idx] in general. That works as expected. However when it's used inside an is expression. The is-expression's type gets evaluated _before_ executes the type function ctfe And during that time type-array[idx] is not parsed as variable expression. it's parsed as the type of a static array, and assuming that idx is an enum with numeric values so given enum idx := 6; type-array[6] is the type of static array. I am still thinking about how to fix this.
Oct 27 2020