import std.stdio
, std.typecons
, std.traits
, std.algorithm
, std.range
, std.container
, conv = std.conv
, std.format;
// This could also be done with bare templates instead of a struct
// and with mixin-ed free functions, allowing natural overloading
// without the awkward `A.stuff` all over the place
// I'm tired, though.
void main() {
with(Reals)
to_str(add(one, one)).writeln();
with(Complex)
to_str(add(one, one)).writeln();
with(Quaternion)
to_str(add(one, one)).writeln();
}
/// "sig"
template isDivAlgebra(alias Testant) {
alias e = Testant;
enum bool isDivAlgebra = __traits(compiles, {
alias K = e.kind;
K r;
K function(K) _conj = e.conj;
K function() _zero = &e.zero;
K function() _one = &e.one;
bool function(K) _zero_chk = e.zero_chk;
K function(K, K) _add = e.add;
K function(K, K) _sub = e.sub;
K function(K, K) _mul = e.mul;
K function(K) _inv = e.inv;
string function(K) _to_str = e.to_str;
});
}
/// BareReals struct
//template BareReals() {
struct BareReals {
/*template sig(Testant) {
enum bool sig = isDivAlgebra!Testant;
}*/
public:
alias kind = float;
static:
enum conj = (float x) pure => x;
float zero() @property pure { return 0.0f; }
float one() @property pure { return 1.0f; }
enum zero_chk = (float x) pure => x == 0.0f;
enum add = (float x, float y) pure => x + y;
enum sub = (float x, float y) pure => x - y;
enum mul = (float x, float y) pure => x * y;
enum inv = (float x) pure => 1.0f / x;
enum to_str = (float x) => std.format.format("%g", x);
}
static if(isDivAlgebra!(BareReals))
alias BareReals Reals;
//mixin BareReals!() Reals;
//static assert( is( typeof(Reals.one) == Reals.kind function() ) );
//static assert( is( Complex.NewKind == Quaternion.NewKind ) );
/// functor "G"
template G(alias Alg)
if(isDivAlgebra!Alg) {
//template G() {
struct G {
public:
alias A = Alg;
// Using templates here isn't working T-T I don't get all the semantics yet
/*enum newKind = "NewKind_" ~ Alg.kind.stringof;
mixin(`struct ` ~ newKind ~ ` {
A.kind r;
A.kind i;
}`);
alias kind = id!(mixin(newKind));/**/
struct NewKind {
A.kind r;
A.kind i;
}
alias kind = NewKind;
static:
enum conj = (kind x) pure => kind(A.conj(x.r), A.sub(A.zero(), x.i));
auto zero() @property pure { return kind(A.zero, A.zero); }
auto one() @property pure { return kind(A.one, A.zero); }
enum zero_chk = (kind x) => A.zero_chk(x.r) && A.zero_chk(x.r);
enum add = (kind x, kind y) pure => kind( A.add(x.r, y.r), A.add(x.i, y.i) );
enum sub = (kind x, kind y) pure => kind( A.sub(x.r, y.r), A.sub(x.i, y.i) );
enum mul = (kind x, kind y) pure {
return kind(
A.sub( A.mul( x.r, y.r ), A.mul( A.conj(x.i), y.i ) )
, A.add( A.mul(x.r, y.i), A.mul(x.i, y.r) )
);
};
enum inv = (kind x) pure {
auto d = A.inv( A.add( A.mul(A.conj(x.i), x.i), A.mul(A.conj(x.r), x.r) ) );
return kind( A.mul(d, A.conj(x.r)), A.sub(A.zero(), A.mul(d, x.i)) );
};
enum to_str = (kind x) => (A.to_str(x.r) ~ ", " ~ A.to_str(x.i));
}
//static assert(isDivAlgebra!( G!() ) );
}
/**/alias Complex = G!Reals;
alias Quaternion = G!Complex;/**/
/*mixin G!Reals Complex;
alias G!Reals Complex_;
mixin G!(G!(BareReals!())) Quaternion;/**/
alias id(alias token) = token;
aW1wb3J0IHN0ZC5zdGRpbwoJLCBzdGQudHlwZWNvbnMKCSwgc3RkLnRyYWl0cwoJLCBzdGQuYWxnb3JpdGhtCgksIHN0ZC5yYW5nZQoJLCBzdGQuY29udGFpbmVyCgksIGNvbnYgPSBzdGQuY29udgoJLCBzdGQuZm9ybWF0OwoKCi8vIFRoaXMgY291bGQgYWxzbyBiZSBkb25lIHdpdGggYmFyZSB0ZW1wbGF0ZXMgaW5zdGVhZCBvZiBhIHN0cnVjdCAKLy8gYW5kIHdpdGggbWl4aW4tZWQgZnJlZSBmdW5jdGlvbnMsIGFsbG93aW5nIG5hdHVyYWwgb3ZlcmxvYWRpbmcKLy8gd2l0aG91dCB0aGUgYXdrd2FyZCBgQS5zdHVmZmAgYWxsIG92ZXIgdGhlIHBsYWNlCgovLyBJJ20gdGlyZWQsIHRob3VnaC4KCgp2b2lkIG1haW4oKSB7Cgl3aXRoKFJlYWxzKQoJCXRvX3N0cihhZGQob25lLCBvbmUpKS53cml0ZWxuKCk7CgoJd2l0aChDb21wbGV4KQoJCXRvX3N0cihhZGQob25lLCBvbmUpKS53cml0ZWxuKCk7CgkJCgl3aXRoKFF1YXRlcm5pb24pCgkJdG9fc3RyKGFkZChvbmUsIG9uZSkpLndyaXRlbG4oKTsKCQoJCn0KCgovLy8gInNpZyIKdGVtcGxhdGUgaXNEaXZBbGdlYnJhKGFsaWFzIFRlc3RhbnQpIHsKCQlhbGlhcyBlID0gVGVzdGFudDsKCQkKCQllbnVtIGJvb2wgaXNEaXZBbGdlYnJhID0gX190cmFpdHMoY29tcGlsZXMsIHsKCQkJYWxpYXMgSyA9IGUua2luZDsKCQkJSyByOwoJCQlLIGZ1bmN0aW9uKEspIF9jb25qID0gZS5jb25qOwoJCQlLIGZ1bmN0aW9uKCkgX3plcm8gPSAmZS56ZXJvOwoJCQlLIGZ1bmN0aW9uKCkgX29uZSA9ICZlLm9uZTsKCQkJYm9vbCBmdW5jdGlvbihLKSBfemVyb19jaGsgPSBlLnplcm9fY2hrOwoJCQlLIGZ1bmN0aW9uKEssIEspIF9hZGQgPSBlLmFkZDsKCQkJSyBmdW5jdGlvbihLLCBLKSBfc3ViID0gZS5zdWI7CgkJCUsgZnVuY3Rpb24oSywgSykgX211bCA9IGUubXVsOwoJCQlLIGZ1bmN0aW9uKEspIF9pbnYgPSBlLmludjsKCQkJc3RyaW5nIGZ1bmN0aW9uKEspIF90b19zdHIgPSBlLnRvX3N0cjsKCQl9KTsKCX0KCgovLy8gQmFyZVJlYWxzIHN0cnVjdAovL3RlbXBsYXRlIEJhcmVSZWFscygpIHsKc3RydWN0IEJhcmVSZWFscyB7CgoJLyp0ZW1wbGF0ZSBzaWcoVGVzdGFudCkgewoJCWVudW0gYm9vbCBzaWcgPSBpc0RpdkFsZ2VicmEhVGVzdGFudDsKCX0qLwoJCgkKCXB1YmxpYzoKCWFsaWFzIGtpbmQgPSBmbG9hdDsKCQoJc3RhdGljOgoJZW51bSBjb25qID0gKGZsb2F0IHgpIHB1cmUgPT4geDsKCglmbG9hdCB6ZXJvKCkgQHByb3BlcnR5IHB1cmUgeyByZXR1cm4gMC4wZjsgfQoJCglmbG9hdCBvbmUoKSBAcHJvcGVydHkgcHVyZSB7IHJldHVybiAxLjBmOyB9CgoJZW51bSB6ZXJvX2NoayA9IChmbG9hdCB4KSBwdXJlID0+IHggPT0gMC4wZjsKCQoJZW51bSBhZGQgPSAoZmxvYXQgeCwgZmxvYXQgeSkgcHVyZSA9PiB4ICsgeTsKCgllbnVtIHN1YiA9IChmbG9hdCB4LCBmbG9hdCB5KSBwdXJlID0+IHggLSB5OwoJCgllbnVtIG11bCA9IChmbG9hdCB4LCBmbG9hdCB5KSBwdXJlID0+IHggKiB5OwoJCgllbnVtIGludiA9IChmbG9hdCB4KSBwdXJlID0+IDEuMGYgLyB4OwoJCgllbnVtIHRvX3N0ciA9IChmbG9hdCB4KSA9PiBzdGQuZm9ybWF0LmZvcm1hdCgiJWciLCB4KTsKfQoKc3RhdGljIGlmKGlzRGl2QWxnZWJyYSEoQmFyZVJlYWxzKSkKCWFsaWFzIEJhcmVSZWFscyBSZWFsczsKCS8vbWl4aW4gQmFyZVJlYWxzISgpIFJlYWxzOwoKLy9zdGF0aWMgYXNzZXJ0KCBpcyggdHlwZW9mKFJlYWxzLm9uZSkgPT0gUmVhbHMua2luZCBmdW5jdGlvbigpICkgKTsKLy9zdGF0aWMgYXNzZXJ0KCBpcyggQ29tcGxleC5OZXdLaW5kID09IFF1YXRlcm5pb24uTmV3S2luZCApICk7Ci8vLyBmdW5jdG9yICJHIgp0ZW1wbGF0ZSBHKGFsaWFzIEFsZykKCWlmKGlzRGl2QWxnZWJyYSFBbGcpIHsKCQoJLy90ZW1wbGF0ZSBHKCkgewoJc3RydWN0IEcgewoJCXB1YmxpYzoKCQkKCQlhbGlhcyBBID0gQWxnOwoJCQoJCS8vIFVzaW5nIHRlbXBsYXRlcyBoZXJlIGlzbid0IHdvcmtpbmcgVC1UIEkgZG9uJ3QgZ2V0IGFsbCB0aGUgc2VtYW50aWNzIHlldAoJCS8qZW51bSBuZXdLaW5kID0gIk5ld0tpbmRfIiB+IEFsZy5raW5kLnN0cmluZ29mOwoJCW1peGluKGBzdHJ1Y3QgYCB+IG5ld0tpbmQgfiBgIHsKCQkJQS5raW5kIHI7CgkJCUEua2luZCBpOwoJCX1gKTsKCQkKCQlhbGlhcyBraW5kID0gaWQhKG1peGluKG5ld0tpbmQpKTsvKiovCgkJCgkJc3RydWN0IE5ld0tpbmQgewoJCQlBLmtpbmQgcjsKCQkJQS5raW5kIGk7CgkJfQoJCWFsaWFzIGtpbmQgPSBOZXdLaW5kOwoJCQoJCXN0YXRpYzoKCQllbnVtIGNvbmogPSAoa2luZCB4KSBwdXJlID0+IGtpbmQoQS5jb25qKHguciksIEEuc3ViKEEuemVybygpLCB4LmkpKTsKCQkKCQlhdXRvIHplcm8oKSBAcHJvcGVydHkgcHVyZSB7IHJldHVybiBraW5kKEEuemVybywgQS56ZXJvKTsgfQoJCQoJCWF1dG8gb25lKCkgQHByb3BlcnR5IHB1cmUgeyByZXR1cm4ga2luZChBLm9uZSwgQS56ZXJvKTsgfQoJCQoJCWVudW0gemVyb19jaGsgPSAoa2luZCB4KSA9PiBBLnplcm9fY2hrKHgucikgJiYgQS56ZXJvX2Noayh4LnIpOwoJCQoJCWVudW0gYWRkID0gKGtpbmQgeCwga2luZCB5KSBwdXJlID0+IGtpbmQoIEEuYWRkKHguciwgeS5yKSwgQS5hZGQoeC5pLCB5LmkpICk7CgkJZW51bSBzdWIgPSAoa2luZCB4LCBraW5kIHkpIHB1cmUgPT4ga2luZCggQS5zdWIoeC5yLCB5LnIpLCBBLnN1Yih4LmksIHkuaSkgKTsKCQkKCQllbnVtIG11bCA9IChraW5kIHgsIGtpbmQgeSkgcHVyZSB7CgkJCXJldHVybiBraW5kKAoJCQkJQS5zdWIoIEEubXVsKCB4LnIsIHkuciApLCBBLm11bCggQS5jb25qKHguaSksIHkuaSApICkKCQkJCSwgQS5hZGQoIEEubXVsKHguciwgeS5pKSwgQS5tdWwoeC5pLCB5LnIpICkKCQkJKTsKCQl9OwoJCQoJCWVudW0gaW52ID0gKGtpbmQgeCkgcHVyZSB7CgkJCWF1dG8gZCA9IEEuaW52KCBBLmFkZCggQS5tdWwoQS5jb25qKHguaSksIHguaSksIEEubXVsKEEuY29uaih4LnIpLCB4LnIpICkgKTsKCQkJcmV0dXJuIGtpbmQoIEEubXVsKGQsIEEuY29uaih4LnIpKSwgQS5zdWIoQS56ZXJvKCksIEEubXVsKGQsIHguaSkpICk7CgkJfTsKCQkKCQllbnVtIHRvX3N0ciA9IChraW5kIHgpID0+IChBLnRvX3N0cih4LnIpIH4gIiwgIiB+IEEudG9fc3RyKHguaSkpOwoJfQoJCgkvL3N0YXRpYyBhc3NlcnQoaXNEaXZBbGdlYnJhISggRyEoKSApICk7Cn0KCi8qKi9hbGlhcyBDb21wbGV4ID0gRyFSZWFsczsKYWxpYXMgUXVhdGVybmlvbiA9IEchQ29tcGxleDsvKiovCgovKm1peGluIEchUmVhbHMgQ29tcGxleDsKYWxpYXMgRyFSZWFscyBDb21wbGV4XzsKbWl4aW4gRyEoRyEoQmFyZVJlYWxzISgpKSkgUXVhdGVybmlvbjsvKiovCgphbGlhcyBpZChhbGlhcyB0b2tlbikgPSB0b2tlbjsKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoK