On Friday, 1 November 2013 at 09:31:41 UTC, Philippe Sigaud wrote:
On Thu, Oct 31, 2013 at 8:59 PM, Craig Dillabaugh <
cdill...@cg.scs.carleton.ca> wrote:
Thanks, I will try both your, and Bearophile's ideas and see
if I
can figure out how they work.
reduce takes a range and eagerly (that is, not lazily) builds a
value from
it. In your case, it builds the squared distance between two
points. The
returned value can be anything: a numerical value, but also
another range,
a complex object, an so on. As long as it can be built
increasingly,
you're good.
Given a range [a,b,c,..., z] and a binary function f,
reduce!(f)([a,b,c,...]) calculates f(a,b), then f(f(a,b), c),
up to f(...
f( f( f(a,b),c), d), ...,z).
The only question is whether you give it a seed value, or if it
takes the
first range element as seed (f(seed, a), f(f(seed,a),b) and
son on).
std.algorithm.reduce provides both overloads.
Note the only thing you get is the final result, not the
internal f(f(...'s
applications.
If you want a sum:
reduce!( (result,elem) => result + elem )(range)
or
reduce!( (result,elem) => result + elem )(range, 0)
Sum of squares:
reduce!( (result, elem) => result + elem^^2 )(range, 0)
In your case, the basic element is a tuple, coming from zip.
Access to the
two elements is done with [0] or [1]. So:
reduce!( (result, elem) => result + (elem[0]-elem[1])^^2
)(zippedRange, 0)
This is really where my problem arose. I understood everything up
to here, but I sort of had this idea, "hey zip returns a tuple so
that somehow the compiler
was going to figure out for me that function(e) has two values"
and is thus
a binary function so this should work (the 0.0 on the end was my
start value):
reduce!(function(e) { return (e[1]-e[0])*(e[1]-e[0]); })(0.0)
However, of course the compiler see's the tuple as just one value
- which is where I made my mistake.
Of course, it would be easy to write a small n-range reduce
helper
function, that takes n ranges and reduces them in parallel:
reduce!( (result, a, b) => result + (a-b)^^2 )(rangeA, rangeB,
0)
Note that reduce is a versatile function: you can duplicate
filter and map
functionalities with it. The only thing to remember is that,
compared to
other iteration algorithm/ranges, it's eager. Don't use it on
an infinite
range!
We could also have a slightly different version that lazily
produces the
intermediate results as a range. IIRC, it's called 'scan' in
Haskell. It's
sometimes interesting to have it: you can interrupt the ongoing
calculation
when the result is 'good enough', not waiting for the entire
input range to
be consumed.