Conversation

here’s a random visualization of three ways to represent math operations, because I wanted to look at this for myself and I thought others might be interested too

infix notation with order of operations and associativity:

((1 + 2 + 3) * 4 ** 5 * 6 / 7) ** 8

the same infix notation with parenthesis replacing any possible ambiguity about order of operations:

((1 + 2 + 3) * (4 ** 5) * (6 / 7)) ** 8

the same equation, doing the parenthesis thing again, except I simplified it by replacing / 7 with * 7 ** -1 which I find helpful, at least, to turn division into a symmetrical operation:

((1 + 2 + 3) * (4 ** 5) * 6 * (7 ** -1)) ** 8

now here’s the same equation in FORTH-style reverse Polish notation:

1 2 + 3 + 4 5 ** * 6 * 7 / 8 **

and here it is in Polish notation:

** 8 / 7 * 6 * ** 4 5 + + 1 2 3

here it is in Lisp-style Polish notation:

(** 8 (/ 7 (* 6 (** 4 5) (+ 1 2 3))))

okay now just for the sake of trying something weird, let’s do Lisp-style syntax again except the operator goes at the end instead of the beginning:

((((1 2 3 +) (4 5 **) 6 *) 7 /) 8 **)

excluding infix notation, which do y’all find most readable?

75% reverse Polish notation: `1 2 + 3 + 4 5 ** * 6 * 7 / 8 **`
0% Polish notation: `** 8 / 7 * 6 * ** 4 5 + + 1 2 3`
25% Lisp-style Polish notation: `(** 8 (/ 7 (* 6 (** 4 5) (+ 1 2 3))))`
0% Lisp-style reverse Polish notation: `((((1 2 3 +) (4 5 **) 6 *) 7 /) 8 **)`
1
2
1

I’m heavily biased because I’ve written a smallish amount of Forth code, but I really really like Forth-style reverse Polish notation. it’s incredibly easy for me to read because I can read it left-to-right and I don’t need to keep track of parens - though of course infix notation is still the easiest for me

I find regular Polish notation to be the hardest to read. I have to read it from right to left which is very unintuitive to me

surprisingly, the next easiest to read for me is Lisp notation, with my made up reverse-Lisp notation being harder to read than that? I don’t understand why - I really thought that emulating RPN with Lisp parens would be easier for me but somehow it isn’t, even though I do still have to read the Lisp notation from right to left

1
0
1

@kasdeya remind us to tell you about wasm's stack instructions again sometime

1
0
1

@tempest oohh I would love that. I’ve always thought Forth’s stack manipulation was so cool

0
0
0

@kasdeya All of these hurt my brain :( The parentheses-added Lispy versions work better for me, with the Polish+Lisp the best, since they visually group the subexpressions so I can reason more easily about which part I hold fixed and which part I simplify. But I'm so used to standard mathematical notation, and infix ASCII approximations get the closest to that for me.

1
0
1

@kasdeya The Polish and RPN versions are hardest for me for exactly the same reason they're so easy to implement: they're meant to be read and processed left-to-right, with a stack of intermediate values (or incomplete operations) carrying the current state of evaluation. And I mentally find it easier to rewrite one expression compositionally than to hold an intermediate structure in my head.

1
0
1

@liese ooh interesting! when you say “rewrite one expression compositionally” are you talking about doing a transformation like this?:

(+ 1 2 3) -> 1 + 2 + 3

I’m not totally sure what compositionally means mathematically but I looked it up and it seems to be a way of turning two functions into one new function. is that what you’re talking about?

1
0
0

@kasdeya Not exactly 😅So when I want to simplify something like `1 + 2*3`, it's easy for me to mentally split this into a part that isn't going to immediately change (`1 + _`), and a part that can be immediately simplified (`2 * 3`). I can deal with the smaller, simpler problem directly (`2 * 3` is `6`), and then plug the result back into the larger context (giving `1 + 6`). I end up with the same kind of thing I started with, and can repeat this process again.

1
0
1

@kasdeya The idea of "compositionality" is that you can break a problem or structure down into smaller pieces that you can independently analyze, and put them back together the same way you started. Above, I decomposed the expression into a context and a redex ("reducible expression"), analyzed the redex (it simplifies to 6), then lifted my analysis back into the larger context.

1
0
1

@kasdeya More broadly, "compositionality" is a kind of category-theoretic attitude that says that the most understandable systems are the ones that aren't "more than the sum of their parts". If the behavior of the whole can be understood and predicted from the behavior of the pieces, then the system is compositional. (This is what makes concurrency hard, btw -- it's not usually compositional! You can get wild interleavings that weren't possible with individual sequential programs.)

2
0
1

@kasdeya All this is to say that the Polish and RPN notations are hard for me to break down visually into smaller pieces that I can simplify independently. I know it's *possible*, but the lack of parentheses means I can't quickly identify a substring that makes sense in isolation.

0
0
1

@liese okay I’ve thought about this a lot and I think I understand what you’re saying! so code could be considered compositional if it’s made up of abstractions that have no side effects on each other - they just encapsulate some kind of self-contained functionality. for example if I call a function, the context would be the function call (from the outside) and whatever code is going to use the return value of the call, and the redex would be the code for the function itself

but if the function had some kind of side effect, then it wouldn’t be compositional anymore, because you can’t neatly encapsulate all of the effects of that function into a redex

am I getting it right?

1
0
0

@kasdeya yes, that's definitely a very close angle onto what i'm saying! i was originally just talking about the specific arithmetic expression you gave; arithmetic as a semantic concept is "compositional" no matter which syntactic notation you use. what i was specifically poking at is how hard it is for me to "see" the syntax tree, the order of operations and the extents of the subexpressions, when there's no parentheses or other visual cues like PEMDAS

1
0
0

@kasdeya (interlude: sorry for all the longwinded replies, i am a very wordy person 💀)

1
0
0

@kasdeya but the thing you're talking about is super closely related, just in the semantics instead of the syntax. Haskellers and other pure functional programmers call it "equational reasoning": since we know that 2*3 = 6, we also know that f(2*3) = f(6) no matter what `f` is. it's definitely a huge reason i prefer pure, side-effect-free programming

1
0
0

@kasdeya syntactically, i find something like "+ 1 * 2 3" to be harder to read because if i take a random substring like "1 * 2", i can't compute that to a result like what i want to compute the original string to. the only reasonable interpretation is as "a sequence of commands", in which case the semantics *is* compositional, but it's also totally inappropriate for helping me to simplify the original expression, because executing it requires knowing what the current stack is

1
0
0

@kasdeya if i want to properly simplify the expression `+ 1 * 2 3`, i either have to execute the whole thing from the start, or get lucky and find a substring that doesn't read the prior contents of the stack (like `* 2 e`). but the syntax doesn't help me *find* those substrings, especially with longer expressions, so practically speaking i can't understand a Polish notation expression easily by decomposing it -- at least, not without a lot more mental effort

2
0
0

@kasdeya the key thing for me is that this is all human and psychological, and only tangentially technical. the problem is that *I* am incapable of easily seeing how the notation cleaves into independently-understandable substrings.

1
0
0

@kasdeya oops, meant `* 2 3` here. dratted phone keyboard

0
0
0

@kasdeya just adding parentheses, as in `(+ 1 (* 2 3))`, does *wonders* for my reading comprehension, because almost all the hard work of finding the "right" substrings is already done for me

0
0
0