Functional vs simple code

ixid nuaccount at gmail.com
Tue Oct 2 18:21:47 PDT 2012


On Tuesday, 2 October 2012 at 22:13:10 UTC, Timon Gehr wrote:
> On 10/03/2012 12:11 AM, Timon Gehr wrote:
>> ...
>>
>> $ cat ixidbench.d
>> module main;
>> import std.stdio, std.algorithm, std.range, std.datetime;
>>
>> enum MAX = 10_000_000_000UL;
>>
>> void main() {
>>     StopWatch sw;
>>     sw.start;
>>
>>     auto sum1 = MAX.iota.map!(x => x * x).reduce!"a + b";
>>
>>     sw.stop;
>>     sw.peek.msecs.writeln("msecs");
>>     sum1.writeln;
>>     sw.reset;
>>     sw.start;
>>
>>     ulong sum2 = 0;
>>     foreach(i;0..MAX)
>>         sum2 += i * i;
>>
>>     sw.stop;
>>     sw.peek.msecs.writeln("msecs");
>>
>>     sum2.writeln;
>> }
>> $ ldmd2 -O -release -inline ixidbench.d -ofixidbench
>> $ ./ixidbench
>> 6528msecs
>> 7032546979563742720
>> 7518msecs
>> 7032546979563742720
>
> $ gdmd -O -release -inline ixidbench.d -ofixidbench
> $ ./ixidbench
> 11250msecs
> 7032546979563742720
> 11233msecs
> 7032546979563742720

While fiddling with this I came across something that seems odd 
in the behaviour of reduce and wondered if it's intended. It 
rather limits the usefulness of reduce with UFCS to "a + b" and 
"a - b".

Reduce works correctly when provided with a seed argument:

reduce!"a + b + 2"(0, [1,1,1]).writeln; // == 9 as expected

With UFCS I see no elegant way to reduce a chain with a more 
sophisticated reduce argument than the two simple ones listed 
above because the operation is not carried out on the first array 
element, used as the seed. This means:

[1,1,1].reduce!"a + b + 2".writeln; // == 7

which is useless and could easily trip people up because the 
intuitive expectation is that it will act like the seed example. 
If I am wrong in that expectation what is a use case for the 
seedless behaviour? Is there a way of writing the operation to 
give the same answer as the seed answer?

The element in position 0 should surely have +2 added to itself, 
it's only being the seed out of convenience isn't it? Instead we 
get 1 + (1 + 2) + (1 + 2). The order of reduce's arguments, 
(seed, range) prevent it being used with UFCS properly. If it 
were (range, seed) then there would be no problem:

[1,1,1].reduce!"a + b + 2"(0).writeln; // == 9


More information about the Digitalmars-d-learn mailing list