[HN Gopher] Inverse Parentheses
___________________________________________________________________
Inverse Parentheses
Author : mighty-fine
Score : 66 points
Date : 2025-12-22 08:29 UTC (14 hours ago)
(HTM) web link (kellett.im)
(TXT) w3m dump (kellett.im)
| tromp wrote:
| Using Brave on MacOS, I cannot scroll the page to see the entire
| text. On Firefox, it scrolls fine.
| guessmyname wrote:
| Same in Safari. It has something to do with the
| :root { [...] overflow: hidden scroll;
| container-type: size; [...] }
|
| in the main CSS file: https://kellett.im/theme/main.css
| auggierose wrote:
| Cannot scroll on Safari on macOS, either. What also doesn't
| work is making the font smaller / larger.
| TerraHertz wrote:
| Splendid. Someone found a way to break Browser Scrolling.
| (Firefox 115.16 for Win7)
|
| Well done.
| bananaflag wrote:
| > Have you ever noticed that lots of programming languages let
| you use parentheses to group operands, but none use them to
| ungroup them?
|
| Since this doesn't exist in practice, shouldn't the article
| author first explain what they mean by that?
| Smaug123 wrote:
| The examples at the end show that it's syntax for "parse such
| that this expression is _not_ grouped ". Essentially I guess
| this could be modelled as an operator `(_+_)` for every
| existing operator `_+_`, which has its binding precedence
| negated.
| pxeger1 wrote:
| I don't understand
| carderne wrote:
| I was hoping the parentheses themselves would be flipped. Like
| this:
|
| > 1 + )2 * 3(
|
| (1 + 2) * 3
| dgoldstein0 wrote:
| Same.
|
| That said if you try to use that with ordinary parentheses
| usage it would get ambiguous as soon as you nest them
| chrisweekly wrote:
| Wait, no. It makes no sense to use the same characters! An
| "inverted" opening parens is visually identical to a "normal"
| closing parens. IMHO the entire proposition is inane.
| AmbroseBierce wrote:
| I think surrounding the operand would make slightly more sense,
| as in 1 + 2 (*) 3 as if it's a "delayed form" of the operation
| that it represents.
| SyzygyRhythm wrote:
| If you do both (use flipped parentheses around the
| operators), it makes even more sense, and makes the parsing
| trivial to boot: just surround the entire expression with
| parentheses and parse normally. For instance: 1 + 2 ) _( 3
| Becomes (1 + 2 )_ ( 3) Which is actually just what the author
| wants. You might even want multiple, or an arbitrary numbers
| of external parentheses. Say we want to give the divide the
| least precedence, the multiply the middle, and the add the
| most. We could do that like: 1 + 2 )/( 3 )) _(( 4 Surround it
| with two sets of parens and you have: ((1 + 2 ) /( 3 ))_((
| 4)) I haven't just proved to myself this always does what you
| expect, though...
| louthy wrote:
| I'm all for terseness in blog writing, but I think the author
| forgot to add the content. I know nothing more than I did when I
| opened it.
| brabel wrote:
| And yet, this is the top entry on HN right now?! How does that
| happen??
| throwaway150 wrote:
| I read the article twice and still doesn't make sense. I
| tried to make sense but no matter how I slice and dice the
| article, the "inverse parentheses" idea seems inconsistent or
| ill defined.
|
| Two comments here which explain the ill-definedness of it:
|
| https://news.ycombinator.com/item?id=46352560
|
| https://news.ycombinator.com/item?id=46352697
| Philpax wrote:
| Engagement from people trying to figure it out :-)
| xeonmc wrote:
| The blue/gold dress of HN nerd sniping
| TeodorDyakov wrote:
| Where do stars live? Thats what I wonder.
| HansP958 wrote:
| The concept of "inverse parentheses" that unbundle operators is
| brilliant! The tokenizer hack (friendliness score by parenthesis
| depth, inspired by Python INDENT/DEDENT) + precedence climbing
| for infinite levels is elegant - parsing solved without
| convoluted recursive grammar. kellett
|
| I love the twist: reversing the friendly levels gives you a
| classic parser, and it opens up crazy experiments like whitespace
| weakening. Have you tested it on non-arithmetic ops
| (logical/bitwise) or more complex expressions like ((()))?
| istjohn wrote:
| It's not just brilliant, it's earth-shattering.
| codegladiator wrote:
| llm generated comment
| NetMageSCW wrote:
| I am sure your comment is almost always wrong whenever you
| use it.
| Philpax wrote:
| Echoing the sentiment that I'm not really sure what I'm meant to
| be looking at here. A motivating example at the start would have
| helped, I think.
| ChanderG wrote:
| Opened this excitedly, thinking I was going to get something
| related to S-expressions/Lisp, was disappointed...
| qsort wrote:
| Am I stupid if I don't get it? What is the intended end state?
| What does "ungroup operands" mean?
| jojobas wrote:
| I'm not sure I'm following but I think what he means is that if
| normal parenthesis around an addition mean this addition must
| precede multiplication, these anti-parenthesis around a
| multiplication have to make addition take place before it.
| suspended_state wrote:
| I think ungrouping make sense if you consider reverse
| parentheses as a syntactic construct added to the language, and
| not replacing the existing parentheses.
|
| For instance, using "] e [" as the notation for reverse
| parentheses around expression e, the second line showing
| reverse parenthese simplification, third line showing the
| grouping after parsing, and the fourth line using postfix
| notation:
|
| A + B * (C + D) * (E + F)
|
| => A + B * (C + D) * (E + F)
|
| => (A + (B * (C + D) * (E + F)))
|
| => A B C D + E F + * * +
|
| A + ] B * (C + D) [ * (E + F)
|
| => A + B * C + D * (E + F)
|
| => ((A + (B * C)) + (D * (E + F)))
|
| => A B C * + D E F * + +
|
| So what ungrouping would mean is to undo the grouping done by
| regular parentheses.
|
| However, this is not what is proposed later in the article.
|
| Possibilities include reversing the priority inside the reverse
| parentheses, or lowering the priority wrt the rest of the
| expression.
| suspended_state wrote:
| I stumbled on this:
|
| https://lobste.rs/s/qoqfwz/inverse_parentheses#c_n5z77w
|
| which should provide the answer.
| ofalkaed wrote:
| Parenthesis used to decrease precedence? Everything outside of
| the parenthesis will be done before what is in the parenthesis?
| TrianguloY wrote:
| Based on this comment
| (https://news.ycombinator.com/item?id=46352389), I think I
| understood the missing first paragraph:
|
| If you have the expression 1+2*3 you have three elements with two
| operands. You need to choose a rule to pick one of them first.
|
| In mathematics, the rule is "*/ then +-" and then from left to
| right. This means that usually first you do 2*3, then 1+.
|
| But what if you do want to make 1+2 first?
|
| There is another alternative, parenthesis. Those mean "do the
| thing inside first" so (1+2)*3 changes the precedence and now you
| do 1+2 first, then *3
|
| The post is asking: with parenthesis you can increase the
| precedence of operations. What if you could decrease it?
|
| Let's use <<>> as another operand (the blog uses parenthesis, but
| that makes it really confusing) this operand means "do the thing
| inside _last_ ". So the expression 1+<<2*3>> means "do 1+ first,
| then 2*3.
|
| The issue is...this doesn't make sense, what the blog is really
| saying is to reduce the precedence of operators. Think the
| expression 1+2<<*>>3 or 1+2(*)3 and now the rule is "the
| parenthesized operators have one precedence less" so
| 1+2(*)3=(1+2)*3
| integricho wrote:
| Thanks, this makes more sense, the blog post was written in a
| really confusing way.
| yccs27 wrote:
| Thanks, writing it as 1+2(*)3 made it click for me.
|
| Reminds me of the '$' operator in Haskell - it lowers the
| precedence of function application, basically being an opening
| parenthesis that's implicitly closed at the end of the line.
| sebtron wrote:
| This seems to be the best guess so far. But then I am
| wondering, how is a (*) b + c
|
| Parsed then? The precedence of '* is bumped down, but does that
| mean it has now strictly lower precedence of '+', or the same?
| In the first case the operation is parsed as
| a * (b + c)
|
| In the second case, the "left to right" rule takes over and we
| get (a * b) + c
|
| And what happens when there are more than 2 priority groups
| Taking C has an example, we have that ' _' has higher
| precedence than '+' which has higher precedence than '<<' [1].
| So a + b * c << d
|
| Means (a + (b * c)) << d
|
| Now I could use the "decrease precedence" operator you proposed
| (possibly proposed by the author?) and write
| a + b (*) c << d
|
| Which then bumps down the precedence of '_' to... One level
| lower? Which means the same level of '+', or a level lower,
| i.e. a new precedence level between '+' and '<<'? Or maybe this
| operator should end up at the bottom of the precedence rank,
| i.e. lower than ','?
|
| The more I think about this, the less sense it makes...
|
| [1]
| https://en.cppreference.com/w/c/language/operator_precedence...
| qsort wrote:
| I don't think that's even well-defined if you have arbitrary
| infix operators with arbitrary precedence and arbitrary
| associativity (think Haskell). If $, & and @ are operators in
| that order of precedence, all right-associatve. Using your
| notation, what is: a & << b $ c >> @ d
|
| If $ is reduced below & but above @ then it's the same as:
| ((a & b) $ c) @ d
|
| If it's reduced below both & and @ then it becomes:
| (a & b) $ (c @ d)
|
| I think conceptualizing parentheses as "increase priority" is
| fundamentally not the correct abstraction, it's school brain in
| a way. They are a way to specify an arbitrary tree of
| expressions, and in that sense they're complete.
| layer8 wrote:
| Clearly we need left-associative and right-associative
| inverse parentheses.
|
| a & )b $ c) @ d would mean ((a & b) $ c) @ d.
|
| a & (b $ c( @ d would mean a & (b $ (c @ d)).
|
| Combining both, a & )b $ c( @ d would mean (a & b) $ (c @ d).
|
| ;)
| Smalltalker-80 wrote:
| Thanks indeed. Using a simple left-to-right evaluation is the
| most logical solution. You can reorder expressions to use less
| parentheses and make them easier to read. E.g.: Smalltalk :-).
| But this requires everyone un-learning their primary school
| maths of e.g. multiply-before-add, so it's not popular. Having
| hand-picked operator precedences complicates things further
| when you allow operator overloading and user defined operators.
| E.g. Swift has special keywords to specify precedence for
| these. Ick...
| NetMageSCW wrote:
| APL uses a simple right to left order of evaluation :)
| jeroen wrote:
| If we actually (as the title seems to imply) invert the
| parentheses, then for your example we get 1+2)*(3 .
|
| Now all you need are the opening and closing parentheses at the
| start and end, and we're back to normal.
| swiftcoder wrote:
| Yeah, that seems a much more robust formulation of the whole
| thing. Flip all parens and enclose the whole string in more
| parens.
| chrisweekly wrote:
| that results in (1+2)*(3)
|
| which is (as GP notes), equivalent to "normal", ie what we
| do today: (1+2)*3
|
| Right?
| sunir wrote:
| Thank you. I thought I was going crazy reading the article
| which doesn't connect open and close parenthesis :: higher
| and lower precedence :: indent and outdent :: +1 and -1 and
| just flip it around to get the opposing polarity.
|
| A real Wesley Crusher moment.
| TacticalCoder wrote:
| > There is another alternative, parenthesis.
|
| Gerald Jay "Jerry" Sussman from Scheme and SICP fame (and
| others) would tell you there's also the prefix notation (but
| ofc only infix makes TFA valid: prefix or postfix makes it
| mostly moot). "3 x 4 x 7 x 19" only looks natural to us because
| we've been taught that notation as toddlers (well, ok, as young
| kids).
|
| But "x 3 4 7 19" is just as valid (Minksy and having to
| understand someting in five different ways or you don't
| understand it etc.).
|
| P.S: also your comment stinks of AI to me.
| astrobe_ wrote:
| well I'll be that guy... If you're going to disturb the normal
| way of righting expressions, RPN or prefix notation (AKA Polish
| Notation) could be a better option. Both don't need parenthesis
| because they don't need precedence/priority rules - which are
| obviously a disadvantage of the infix notation.
|
| The HP 48 famously took the bet of going against the mainstream
| notation. I wonder to what extent this is one of those
| "accidents of history".
|
| RPN moreover simplifies parsing, as shown by the Forth
| language.
|
| Prefix notation, as used by for instance Lisp, doesn't actually
| need parenthesis either; Lisp uses them because it allows
| extensions over basic operators and more generally "variadic"
| operators and functions (e.g. (+ 1 2 3 4)). Without this
| "fancy" feature, prefix notation is unambiguous as well: / + 1
| 2 3. [1]
|
| On a side note, Smalltalk is one of the few languages that said
| "duck it", and require explicit parenthesis instead - which is
| IMO, not an insane approach when you see that for languages
| with 17 levels of priority like C, you end up putting
| parenthesis anyway as soon as the expression is not trivial
| "just to be sure" (e.g. because it mixes boolean operators,
| arithmetic operators and relational operators as in a & 0xF < b
| + 1).
|
| [1] https://en.wikipedia.org/wiki/Polish_notation
| NetMageSCW wrote:
| The HP 48 followed a couple of decades of HP calculators
| using RPN (hardly famous, just an evolution). HP's first
| calculator used RPN.
|
| I recommend https://www.hpmuseum.org/ for more details.
| cubefox wrote:
| Slightly unrelated:
|
| Instead of ordinary brackets, one can also use the dot notation.
| I think it was used in Principia Mathematica or slightly later:
| (A (B (C D)))
|
| would be A . B : C .: D
|
| Essentially, the more dots you add, the stronger the grouping
| operator is binding. The precedence increases with the number of
| dots.
|
| However, this is only a replacement for ordinary parentheses, not
| for these "reverse" ones discussed here. Maybe for reverse, one
| could use groups of little circles instead of dots: deg, degdeg,
| degdegdeg, etc.
| agumonkey wrote:
| could this be the origin of lisp and ML family list notation ?
| agalunar wrote:
| I believe Peano dot notation works the other way 'round;
| A . B : C :. D
|
| would be, as I understand it, equivalent to:
| ((A B) C) D
|
| _The "general principle" is that a larger number of dots
| indicates a larger subformula._ 1
|
| _What if you need to nest parentheses? Then you use more dots.
| A double dot_ (:) _is like a single dot, but stronger. For
| example, we write_ ((1 + 2) x 3) + 4 _as_ 1 + 2 . x 3 : + 4,
| _and the double dot isolates the entire_ 1 + 2 . x 3
| _expression into a single sub-formula to which the_ + 4
| _applies._ 2
|
| A dot can be thought of as a pair of parentheses, ") (", with
| implicit parentheses at the beginning and end as needed.
|
| _In general the "direction" rule for interpreting a formula_
| 'A.B' _will be to first indicate that the center dot "works
| both backwards and forwards" to give first_ 'A).(B', _and then
| the opening and closing parentheses are added to yield_
| '(A).(B)'. _The extra set of pairs of parentheses is then
| reduced to the formula_ (A.B).3
|
| So perhaps one way of thinking about it is that more dots
| indicates more separation.
|
| 1 https://plato.stanford.edu/entries/pm-notation/dots.html
|
| 2 https://blog.plover.com/math/PM.html
|
| 3 https://plato.stanford.edu/entries/pm-notation/dots.html
|
| See also https://plato.stanford.edu/entries/pm-
| notation/index.html and https://muse.jhu.edu/article/904086.
| wvbdmp wrote:
| Regarding the first two footnotes, I'm pretty sure that
| originally the singular form "parenthesis" just refers to the
| aside inserted (by use of brackets, like this) into a sentence.
| Because it sounds like a plural and because of the expression "in
| parenthesis", people probably mistakenly applied the word to the
| pair of symbols, and when that became common, started using the
| real plural "parentheses". This has staying power because it's
| fancy and "brackets" is way overloaded, but historically it's
| probably just wrong and especially nonsensical in math and
| programming, where we don't use them to insert little sidenotes.
| randyrand wrote:
| The core idea: normally, parentheses strengthen grouping:
|
| 1 + (2 * 3) forces 2 * 3 to happen first.
|
| Without them, operator precedence decides. The post asks a
| deliberately strange question:
|
| What if parentheses did the opposite -- instead of grouping
| things tighter, they made them bind less tightly?
| Nevermark wrote:
| I am in the middle of developing a parser for a new language with
| original representation vs. syntax issues to resolve.
|
| Clearly, this was the worst possible time for me to come across
| this brain damaging essay.
|
| I really can't afford it! My mathematical heart can't help taking
| symmetrical precedence control seriously. But my gut is
| experiencing an unpleasant form of vertigo.
| cousin_it wrote:
| Is it the same as flipping every parenthesis to the other side of
| the number it's adjacent to, and then adding enough parentheses
| at the start and end?
|
| For example, (1 + 2) * (3 + 4)
|
| becomes 1) + (2 * 3) + (4
|
| and then we add the missing parentheses and it becomes
| (1) + (2 * 3) + (4)
|
| which seems to achieve a similar goal and is pretty unambiguous.
| Juliate wrote:
| Ha! I was expecting/wondering something about the semantics of )(
| parenthesis (which I have no idea what it could be, but... why
| not?)
| Lerc wrote:
| I think reading this let me experience the feeling a Bene
| Gesserit has when they hear about a preborn.
| 0_gravitas wrote:
| Working with lisp quickly made me realize how over-rated operator
| precedence (or even the concept of "operators") is. All such
| effort and early grade-school hours spent on this arbitrary
| short-hand instead of treating the operations themselves as
| functions and embracing the divine order of (more) parens.
| NetMageSCW wrote:
| Do you really like Lisp?
| 0_gravitas wrote:
| Disclaimer: I used the /royal/ LISP--as in the 'lisp family'-
| my introduction, and language of choice, has been Clojure
| (who's qualification as a Lisp is technically contended by
| certain fundamentalists), but it is still quite paren-based
| either-way.
|
| And I do, I bounced off it the first time long ago, and
| really took to it the second go around, its been my daily
| driver at home and work for some years now- it brings me
| great joy.
| tonnydourado wrote:
| The footnotes are top-tier ADHD. Particularly loved the footnote
| on a footnote, 10/10.
| munchler wrote:
| Prompt: Suggest a topic for a short blog post that will nerd-
| snipe as many readers as possible while making no actual sense at
| all.
|
| System: How about "Inverse Parentheses"? We can write the entire
| article without ever defining what it means. Nerds will be unable
| to resist.
| teo_zero wrote:
| The real question is, why does Python even have parentheses? If
| semantic indent is superior to braces, it ought to beat
| parentheses, too. The following should yield 14:
| a = 2 * 3 + 4
| calmbonsai wrote:
| The singular for parenthesis is paren.
| kazinator wrote:
| I've played with operator precedence parsing earlier this year to
| produce an infix implementation for TXR Lisp.
|
| Documentation entry point: https://www.nongnu.org/txr/txr-
| manpage.html#N-BEB6083E
|
| I may have invented something new, which I called "Precedence
| Demotion". I did some research regarding prior art for this exact
| thing but didn't find it.
|
| https://www.nongnu.org/txr/txr-manpage.html#N-89023B87
|
| LOL, I see I have a bug in the quadratic-roots example (not
| related to the above). The example has correct results for the
| given inputs because a is 1.
|
| It's ironic: you add infix to Lisp and, wham, you make a bugeroo
| because of infix that would never happen in prefix, right in the
| documentation. Like a poetic justice punishment.
___________________________________________________________________
(page generated 2025-12-22 23:02 UTC)