7 ms·
I'd argue that having A*x + A*y + A*z evaluate to A*(x+(A*(y+(A*Z)))) seems wacky because we've been instilled the idea of operator precedence from earl
by maest 7y ago
I'd argue that having
A*x + A*y + A*z
evaluate to
A*(x+(A*(y+(A*Z))))
seems wacky because we've been instilled the idea of operator precedence from early school years. So now, when you see
A*x + A*y + A*z
you instantly do the grouping in your head.
That's all convention really. (And, sure, conventions are powerful).
The point i was making about simplicity was at a mechanical level. The rule "everything is evaluated right-to-left" is mechanically much easier than having, say, 15 different levels of operator precedence[0].
Another point to make here is that + and * are only 2 operators in a much larger list of operators present in a programming language. So even if you have a strong bias towards following the convention and having * have precedence before +, you still need to figure out evaluation order when new operators are included.
There's a spectrum between spartan simplicity and baroque APIs with lots of convenience features and I find that having a sparse set of simple rules is less mentally taxing and more effective than big API surfaces.
[0] https://en.cppreference.com/w/c/language/operator_precedence https://en.cppreference.com/w/c/language/operator_precedence
- kazinator 7y agoThe reason we group A*x + A*y + A*z in our heads somehow is that it has a repeating pattern. Either the grouping is (A*x) + (A*y) + (A*z) Or else it must be A*(x + A)*(y + A)*z. It's not obvious that the A*(x+(A*(y+(A*z)))) interpretation of A*x + A*y + A*z lends itself to manipulations of syntactic units that corresponds to arithmetic in the same way. We can't factor out A. If we divide by A, it just goes to x + A*y + A*z. Then if we divide by A again, we get (x/A) + y + A*z. We don't have the concept of commutative laws being reflected in the ability to simply exchange syntactic elements that are siblings at the same level in the tree. For instance, these are commutative pairs: A*x + A*y + A*z <==> A*x + A*(A*z) + y. We can't lose the parentheses around (A* z) because the interpretation of the syntax doesn't respect the boundaries required to express commutativity. The proper way to eliminate nuisance N-level is Lisp syntax, not some silly version of associativity without precedence. Then we still have those algebraic properties: (+ (* A x) (* A y) (* A z)) --> exchange nodes to commute --> (+ (* A z) (* A y) (A x)) --> factor A: (* A (+ x y z)). It can get cumbersome, but we have a sane way to do algebra by manipulating sanely delimited subtrees in regular ways. People have developed (more importantly, debugged) computer algebra systems in this representation.
- TheRealDevonMcC 7y agoThe preceding discussion is a good example of "whoosh!" because it fails to understand that APL is an array language. It eschews scalar representation like "A1x1 + A2x2 ...". In APL, you would write this as something like "A +.× x". The same lack of understanding of the array context also underlies the earlier comment favoring "standard" order of operation that works well for maybe five functions with three levels of precedence but quickly becomes unwieldy for more functions. Someone else already alluded to this lack of scalability but the power of a strictly positional precedence - not "no precedence" - shows up in array operations. For example, consider reduction by a non-commutative function like "-/A". In the "standard" order of precedence, since all the subtractions are at the same level, this can be restated as the first item in A minus the sum of the remaining items. This is not particularly interesting or useful. However, positional precedence interprets this expression as an alternating sum: (2-3) + (5-9) (for the "A" above). Alternating sum is a common, useful construction in mathematics.