6 ms·
I think there's an opportunity to name variables after their invariant. For example, in the typical sum example, the mutated variable is usually called "sum" o
by skrebbel 8y ago
I think there's an opportunity to name variables after their invariant.
For example, in the typical sum example, the mutated variable is usually called "sum" or "total". But you could also call it sum_from_0_to_i, and then a reader can immediately see that the result is the full sum because i equals the array length. It's like a proof-by-variable-name.
The same trick tends to work as well with less trivial invariants. You get long variable names, but not horribly so.
You can do the same for the accumulator in a reduce/fold operation. Way too often variables in reduce calls (and other recursive functions) have horrible names, making the entire reduce needlessly hard to understand. Naming the accumulator properly solves this:
Eg
const total = array.reduce(
(totalUptoPrevious, current) => totalUptoPrevious + current,
0
);
So much easier to follow! I've often had to look up, when reading a reduce, which argument is the accumulator in this particular language or library. When you use the invariant for the accumulator name, you fix this entirely.
- ummonk 8y agoI mean generally I tend to prefer operations that are commutative and associative, so it really doesn't matter which one is the accumulator. But I still really like your naming, it seems to bridge the gap in making reduces (which are conceptually cleaner) understandable to people who are used to iterative code.
- whatshisface 8y agoFloating point sums are one example of a place where the only usable operator doesn't commute.
- BeetleB 8y agoWhich floating point operator is not commutative? Addition is.
- karmakaze 8y agoAdding smaller magnitude first gives a different result than adding larger magnitudes first due to mixing precisions.
- BeetleB 8y agoIf I read you right, you are saying that if you compute a+b, you'll get a different result than if you compute b+a, if a is tiny and b is huge. I believe this is incorrect. Feel free to show me a counterexample.
- jonsen 8y agoa + b commutes all right, but some-start-value +a +b ... +x does not necessarily.
- JadeNB 8y agoAs rhimenoceros points out, that is a failure of associativity, not commutativity.
- rhymenoceros 8y agoNot quite a+b, but a+b+c reordered may give different results[1]. Example from Python: >>> 0.1+0.2+0.3 0.6000000000000001 >>> 0.2+0.3+0.1 0.6 It's an associativity problem and not a commutative one, however, that is relevant to the original point about folding floating point operations over lists. [1] https://www.quora.com/Is-floating-point-addition-commutative-and-associative https://www.quora.com/Is-floating-point-addition-commutative...
- jonsen 8y ago(small number)+(small number)+ ... +(small number)+(much bigger number) may not give the same result as (much bigger number)+(small number)+(small number)+ ... +(small number)
- 8y ago
- skrebbel 8y agoI find that few practical folds have that property. I mean, you're not going to actually implement "sum" - there's a library function for that. Your reduces are going to be domain specific, and then order often matters, and explicitly accumulating the result on the left (or right) hand side often has a performance impact (eg when building lists).
- kyle-rb 8y agoWhy is 'totalUpToPrevious' better than 'sum' or 'total'? I could see it being good for explaining what a reduce does, but once you know how they work, 'sum' tells you exactly which argument is the accumulator.
- skrebbel 8y agoBecause it underlines that it's the sum of all elements seen so far. It does not just say "yo, this one here is the accumulator", it also implicitly defines the meaning of "accumulator" by saying "and the code that follows will guarantee that it is always the sum of the elements that have been seen so far". It's almost like a spec for the body of the combining function. I recognize that in a codebase where every 10 lines there's a reduce or something similar this may not be necessary, in the exact same way that nobody names a C style loop index variable "current_index". But I find that, even in many functional languages, reduces and custom recursive functions aren't that common because the libraries include so many batteries.
- geoelectric 8y agoI wonder if totalSoFar would be a good tradeoff of precision for conciseness. It's how you're consistently explaining it in plain English, which is a powerful indicator it might be adequate. I do normally call this sort of thing acc or accumulator though. I feel like an understanding of what that specific term means comes with the field expertise, sort of like we can say "LinkedList" and not "ObjectWithPointerToNextObject" and know exactly what that pattern should look like. A lot of CS skill comes down to expanding simple standard names. That's not to say that your approach doesn't have value. It might just be that the toy example doesn't show it off very well. But if you were juggling that 3-way partition, for example, your naming scheme starts making a lot of sense for naming the boundary variables.
- smichel17 8y agoI was thinking a similar thing, but with "runningSum"/"runningTotal".