Jump to page: 1 2
Thread overview
Type programming game
Oct 11
Basile B.
Oct 11
Basile B.
Oct 12
claptrap
6 days ago
claptrap
6 days ago
Stefan Koch
3 days ago
Basile B.
3 days ago
Stefan Koch
3 days ago
Basile B.
3 days ago
Stefan Koch
3 days ago
Basile B.
October 10
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
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
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
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
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
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
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
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
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
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