On Wednesday, 1 April 2015 at 17:51:40 UTC, John Colvin wrote:
On Wednesday, 1 April 2015 at 17:03:34 UTC, Dennis Ritchie wrote:
On Wednesday, 1 April 2015 at 15:22:10 UTC, John Colvin wrote:
Compile Time Function Evaluation (CTFE) is a very powerful tool
to avoid having to enter in to all that C++ style mess.

Yes, CTFE in D really cool. Thanks.

I need to implement arithmetic (addition / subtraction) only use the type system.
That is, such a design does not suit me:

enum Add(Args...) = Args[0] + Args[1];
enum Inc(Args...) = Args[0] + 1;

Don't really see the point. Here's a neat thing that's definitely cheating because although it stores the results in the type system, the arithmetic is done in constant-folding:

struct Integer(int a){}
template Value(T)
{
    static if (is(T == Integer!a, int a))
        enum Value = a;
else static assert(false, "Can't get Value for " ~ T.stringof);
}
alias Inc(T) = Integer!(Value!T + 1);


But if you really insist on it being all type-system (until you wan't the answer of course):

struct Zero{}

template Succ(T)
{
    static if (is(T == Pred!A, A))
                alias Succ = A;
        else
                struct Succ{}
}

template Pred(T)
{
    static if (is(T == Succ!A, A))
                alias Pred = A;
        else
                struct Pred{}
}

enum isPositive(T) = is(T == Succ!A, A);
enum isNegative(T) = is(T == Pred!A, A);
enum isZero(T) = is(T == Zero);

template Add(A, B)
{
        static if (isZero!B)
                alias Add = A;
        else static if (isPositive!B)
                alias Add = Add!(Succ!A, Pred!B);
        else
                alias Add = Add!(Pred!A, Succ!B);
}

template Value(T, int seed = 0)
{
        static if (isZero!T)
                enum Value = seed;
        else static if (isPositive!T)
                enum Value = Value!(Pred!T, seed+1);
        else
                enum Value = Value!(Succ!T, seed-1);
}

unittest
{
        alias One = Succ!Zero;
        alias Two = Succ!One;
        alias MinusThree = Pred!(Pred!(Pred!Zero));
        
        static assert (Value!Zero == 0);
        static assert (Value!One == 1);
        static assert (Value!Two == 2);
        static assert (Value!MinusThree == -3);
        
        static assert (Value!(Add!(One, MinusThree)) == -2);
        static assert (Value!(Add!(One, Two)) == 3);
        static assert (is(Add!(Add!(One, Two), MinusThree) == Zero));
}

If the is() expressions are confusing you, in this case they work like this;

is (T == B!A, A)

means

is T the same type as B instantiated with A, for some type A?

or more succinctly

is T an instantiation of B?

See http://dlang.org/expression.html#IsExpression, it's quite reminiscent of some mathematical set notation.

Reply via email to