Jump to page: 1 2
Thread overview
Type programming game
Oct 10, 2020
Stefan Koch
Oct 11, 2020
Timon Gehr
Oct 11, 2020
Stefan Koch
Oct 11, 2020
Adam D. Ruppe
Oct 11, 2020
Stefan Koch
Oct 11, 2020
Patrick Schluter
Oct 11, 2020
Basile B.
Oct 11, 2020
Stefan Koch
Oct 11, 2020
Basile B.
Oct 12, 2020
claptrap
Oct 13, 2020
Stefan Koch
Oct 13, 2020
Stefan Koch
Oct 14, 2020
claptrap
Oct 14, 2020
Stefan Koch
Oct 17, 2020
Basile B.
Oct 17, 2020
Stefan Koch
Oct 17, 2020
Basile B.
Oct 17, 2020
Stefan Koch
Oct 17, 2020
Basile B.
Oct 27, 2020
Stefan Koch
October 10, 2020
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
October 11, 2020
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");
October 11, 2020
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).

October 11, 2020
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));


October 11, 2020
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.
October 11, 2020
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?
October 11, 2020
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");
---
October 11, 2020
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.
October 11, 2020
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.
October 12, 2020
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;
}
« First   ‹ Prev
1 2