A little challenge...

Philippe Sigaud philippe.sigaud at gmail.com
Fri Feb 26 12:17:14 PST 2010


On Fri, Feb 26, 2010 at 10:07, Norbert Nemec <Norbert at nemec-online.de>wrote:

> Jason House wrote:
>
>> Would sum!( "i", "a[i]*b[i]" ) be acceptable? That should be achievable
>> with a template mixin that does string mixins under the hood.
>>
>
> It is indeed a solution for the problem, but I still don't like it too
> much. For one, writing expressions as strings always feels awkward. Even
> though D can handle these strings at compile time, it just doesn't feel like
> writing native D code.
>
> Beyond this "gut feeling" I also see two technical problems:
>
> * code editors do not recognize the string content as code, so they cannot
> offer syntax highlighting or more advanced language tools
>
> * the syntax does not allow nesting:
>
>        sum(i)( a[i] * sum(j)(b[i,j]*c[j]) )
>

You could use anonymous functions, like this:

sum!( (i,a,b) { return a[i]+b[i];})(array1, array2);

Here I consider a function of an index and some arrays, but you could use
functions on elements:

sum!( (a,b) { return a+b*a;})(array1, array2);

Editors can recognize these functions and they nest (though it's a bit
heavy):

sum!( (a,b) { return a + sum!((b) { return b*b;})(array2) * a)(array1);

A possible implementation for one array can be :

T sum(alias op, T)(T[] array) /* also, RandomAccessRange*/
{
    T result;
    foreach(i, elem; array) result += op(i, array);
    return result;
}

It's quite simplified: I consider op returns a T...

Now, what's interesting is generalizing it somewhat : any number of inputs,
and inputs can be input ranges and not only arrays:

auto sum(alias op, R...)(R ranges) if(allSatisfy!(isInputRange,R))
{
    alias staticMap!(ElementType,R) FrontType;
    FrontType f;
    typeof(op(f)) theSum;
    while(!ranges[0].empty)
    {
        foreach(i, Type; FrontType) { // extracting the fronts
            f[i] = ranges[i].front;
            ranges[i].popFront;
        }
        theSum += op(f);
    }
    return theSum;
}

usage:

int[] ar1 = [0,1,2,3];
int[] ar2 = [4,5,6,7];
auto s = sum!((a,b,c) {return a+b*c;})(ar1,ar2,ar1);
writeln(s); // 44

Note that we could sum ranges with any element type, as long as the .init
value can be summed. float/double being initialiazed to NaN, it's a bit
tricky.

We could adopt std.algorithm 'string functions' trick, to get this syntax,
which I quite like:

auto s = sum!"a+b*c"(ar1, ar2, ar3);

Maybe you could be interested by looking at some modules with these ideas
at:
http://www.dsource.org/projects/dranges

(addendum: another generalization is of course to have two operations: the
'mapping' operation and the 'reducing' operation
like this:
auto sum = mapReduce!("a*b*c+1", "a+b")(range1, range2, range3);
The first function is applied on the elements, the second on the successive
results of the first fun.

Philippe
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.puremagic.com/pipermail/digitalmars-d/attachments/20100226/965dc544/attachment.html>


More information about the Digitalmars-d mailing list