challenge #2: implement the varargs_reduce metafunction
Bruno Medeiros
brunodomedeiros+spam at com.gmail
Tue Jan 23 05:34:38 PST 2007
Andrei Alexandrescu (See Website for Email) wrote:
> My previous post defines max by availing itself of a metafunction called
> varargs_reduce. Your challenge is to define it. varargs_reduce takes an
> alias which it assumes is a function of two arguments, and it defines a
> vararg function that applies that alias repeatedly, similarly to the
> reduce primitive that is present in functional languages. Again, for
> background on functional reduce, see e.g.:
>
> http://www.joelonsoftware.com/items/2006/08/01.html
>
> Define varargs_reduce to deduce the result type properly, and to
> generate code as efficient as possible.
>
>
> Andrei
Here is my try. I assume the reduce type must be exactly the same in all
arguments. Should that not be the case?
As for efficiency, I'm not sure what the requirements are. Is there to
be any parallelization/vectorization considerations? This one, instead
of linear iteration, uses binary recursion to calculate the result, but
for *no particular reason* since its not actually any faster than linear
recursion.
This one seems much more easy that the fist challenge, so I suspect I'm
missing something.
-----------------------------------
//import stdext.stdio;
import std.stdio : writeln = writefln;
static import meta.Util;
// Gets the typeof if not a type already.
template TypeOf(alias ALIAS) {
static if(is(ALIAS)) {
alias ALIAS TypeOf;
} else {
alias typeof(ALIAS) TypeOf;
}
}
// See if the types are the same
template TypeEquals(alias A1, alias A2) {
static if(is(TypeOf!(A1) == TypeOf!(A2)))
const bool TypeEquals = true;
else
const bool TypeEquals = false;
}
// Duplicated template because primitive types do not match aliases :(
template TypeEquals(T1, T2) {
static if(is(T1 == T2))
const bool TypeEquals = true;
else
const bool TypeEquals = false;
}
/***************** varargsReduce ***************/
// Template implicit property workaround
template varargsReduce(alias FN) {
alias varargsReduce_Impl!(FN).varargsReduce_Impl varargsReduce;
}
template varargsReduce_Impl(alias FN) {
static import std.traits;
static assert(is(typeof(FN) == function) || is(typeof(FN) ==
delegate));
alias std.traits.ParameterTypeTuple!(FN) Params;
alias std.traits.ReturnType!(FN) ReduceType;
static assert(Params.length == 2);
//static assert(typeof(FNarg1) == typeof(FNarg2));
static assert(TypeEquals!(Params[0], Params[1]));
//static assert(typeof(FNarg1) == ReduceType);
static assert(TypeEquals!(Params[0], ReduceType));
ReduceType varargsReduce_Impl(ARGS...) (ARGS args) {
pragma(msg, "varargsReduce_Impl! length:" ~
meta.Util.itoa!(ARGS.length));
//static assert(ARGS.length != 0, "Error: no args");
static if(ARGS.length == 1) {
static assert(TypeEquals!(typeof(args[0]), ReduceType));
return args[0];
} else
static if(ARGS.length == 2) {
static assert(TypeEquals!(typeof(args[0]), ReduceType));
static assert(TypeEquals!(typeof(args[1]), ReduceType));
return FN(args[0], args[1]);
} else
static if(ARGS.length >= 3) {
ReduceType val1 = varargsReduce_Impl(args[0 .. ARGS.length/2]);
ReduceType val2 = varargsReduce_Impl(args[ARGS.length/2 ..
ARGS.length]);
return FN(val1, val2);
} else {
static assert(false, "Error: no args");
}
}
}
/***************** Usage ***************/
int sum(int a, int b) {
return a + b;
}
char[] cat(char[] a, char[] b) {
return a ~ b;
}
void main(char[][] args) {
auto result = varargsReduce!(sum)(1, 3, 3, 7);
writeln(result);
auto result2 = varargsReduce!(cat)("H"[], "e"[], "l"[], "l"[], "o"[]);
writeln(result2);
}
----------------- itoa: toStrings an int --------------------
module meta.Util;
template itoa(int i) {
static if (i < 0) {
static const char[] itoa = "-" ~ itoa!(-i);
}
else {
static if (i / 10 > 0) {
static const char[] itoa = itoa(i / 10) ~ "0123456789"[i % 10];
} else {
static const char[] itoa = "0123456789"[i % 10 .. i % 10 + 1];
}
}
}
--
Bruno Medeiros - MSc in CS/E student
http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
More information about the Digitalmars-d
mailing list