Functional vs simple code

jerro a at a.com
Tue Oct 2 21:08:47 PDT 2012


> 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?

The fact that it does something different than the seeded version 
does not make the seedless version useless - in fact, that's what 
makes it useful. A typical use case is to find the maximum of a 
range (there is an example of this in the documentation at 
http://dlang.org/phobos/std_algorithm.html#reduce). If you don't 
know the highest possible value of elements, then you couldn't 
come up with an appropriate seed for this case.

I agree that the difference between the two versions of reduce 
can be a bit confusing. Maybe it would be better if they were 
named differently.

> Is there a way of writing the operation to give the same answer 
> as the seed answer?

In general, no (apart from the silly reduce!f(chain([seed], 
range))). If you want the behavior of the seeded version, use the 
seeded version.

> The element in position 0 should surely have +2 added to 
> itself, it's only being the seed out of convenience isn't it?

No, reduce!f(r) is not merely a syntactic sugar for reduce!f(0, 
r) (you could say it's a syntactic sugar for reduce!f(r.front, 
r.drop(1), though). Making reduce!f(r) be the same as reduce!f(0, 
r) doesn't really make any sense - would you expect [1, 2, 
3].reduce!"a * b" to return 0?  I wouldn't.

> 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

This would be better, yes. Reduce was written before there was 
UFCS, so they couldn't take this into account. I don't know if it 
is possible for this to be changed now, as it would definitely 
break some code.


More information about the Digitalmars-d-learn mailing list